You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将复杂的Microsoft SQL查询转换为视图或表?

将复杂SQL查询转换为视图或表的解决方案

核心问题:原查询无法直接转为视图的原因

SQL Server视图不支持以下特性,但你的查询全部用到了:

  • 变量声明(DECLARE)
  • 临时表(#MaintenanceInfo)
  • 条件分支逻辑(IF)
  • 局部表变量(@HealthState、@ClientState)

方案1:创建带参数的表值函数(推荐,保留参数化能力)

将原查询封装为表值函数,既保留原查询的参数过滤能力,又能像视图一样直接查询。

完整代码

CREATE FUNCTION dbo.DeviceUpdateStatus
(
    @UserSIDs NVARCHAR(10),
    @CollectionID NVARCHAR(10),
    @Locale INT,
    @Categories NVARCHAR(250),
    @Compliant INT,
    @Targeted INT,
    @Superseded INT,
    @ArticleID NVARCHAR(10),
    @ExcludeArticleIDs NVARCHAR(250)
)
RETURNS TABLE
AS
RETURN
(
    WITH HealthState AS (
        SELECT BitMask = 0, StateName = N'Healthy' UNION ALL
        SELECT 1, N'Unmanaged' UNION ALL
        SELECT 2, N'Inactive' UNION ALL
        SELECT 4, N'Health Evaluation Failed' UNION ALL
        SELECT 8, N'Pending Restart' UNION ALL
        SELECT 16, N'Update Scan Failed' UNION ALL
        SELECT 32, N'Update Scan Late' UNION ALL
        SELECT 64, N'No Maintenance Window' UNION ALL
        SELECT 128, N'Distant Maintenance Window' UNION ALL
        SELECT 256, N'Expired Maintenance Window'
    ),
    ClientState AS (
        SELECT BitMask = 0, StateName = N'No Reboot' UNION ALL
        SELECT 1, N'Configuration Manager' UNION ALL
        SELECT 2, N'File Rename' UNION ALL
        SELECT 4, N'Windows Update' UNION ALL
        SELECT 8, N'Add or Remove Feature'
    ),
    Maintenance_CTE AS (
        SELECT
            CollectionMembers.ResourceID,
            NextServiceWindow.NextServiceWindow,
            RowNumber = DENSE_RANK() OVER (PARTITION BY ResourceID ORDER BY NextServiceWindow.NextServiceWindow)
        FROM vSMS_ServiceWindow AS ServiceWindow
        JOIN fn_rbac_FullCollectionMembership(@UserSIDs) AS CollectionMembers 
            ON CollectionMembers.CollectionID = ServiceWindow.SiteID
        JOIN fn_rbac_Collection(@UserSIDs) AS Collections 
            ON Collections.CollectionID = CollectionMembers.CollectionID
            AND Collections.CollectionType = 2 -- 设备集合
        CROSS APPLY ufn_CM_GetNextMaintenanceWindow(ServiceWindow.Schedules, ServiceWindow.RecurrenceType) AS NextServiceWindow
        WHERE NextServiceWindow.NextServiceWindow IS NOT NULL
            AND ServiceWindowType <> 5 -- 排除OSD服务窗口
    ),
    MaintenanceInfo AS (
        SELECT ResourceID, NextServiceWindow
        FROM Maintenance_CTE
        WHERE RowNumber = 1
    ),
    UpdateInfo_CTE AS (
        SELECT
            Systems.ResourceID,
            Missing = COUNT(*)
        FROM fn_rbac_R_System(@UserSIDs) AS Systems
        JOIN fn_rbac_UpdateComplianceStatus(@UserSIDs) AS ComplianceStatus 
            ON ComplianceStatus.ResourceID = Systems.ResourceID
            AND ComplianceStatus.Status = 2 -- 仅筛选"需要安装"的更新
        JOIN fn_rbac_ClientCollectionMembers(@UserSIDs) AS CollectionMembers 
            ON CollectionMembers.ResourceID = ComplianceStatus.ResourceID
        JOIN fn_rbac_UpdateInfo(dbo.fn_LShortNameToLCID(@Locale), @UserSIDs) AS UpdateCIs 
            ON UpdateCIs.CI_ID = ComplianceStatus.CI_ID
            AND UpdateCIs.IsSuperseded IN (@Superseded)
            AND UpdateCIs.CIType_ID IN (1, 8) -- 筛选软件更新和更新捆绑包
            AND UpdateCIs.ArticleID NOT IN (
                SELECT VALUE FROM STRING_SPLIT(@ExcludeArticleIDs, ',')
            )
            AND UpdateCIs.Title NOT LIKE '[1-9][0-9][0-9][0-9]-[0-9][0-9]_Preview_of_%' -- 排除预览更新
        JOIN fn_rbac_CICategoryInfo_All(dbo.fn_LShortNameToLCID(@Locale), @UserSIDs) AS CICategory 
            ON CICategory.CI_ID = ComplianceStatus.CI_ID
            AND CICategory.CategoryTypeName = 'UpdateClassification'
            AND CICategory.CategoryInstanceName IN (@Categories) -- 筛选指定更新分类
        LEFT JOIN fn_rbac_CITargetedMachines(@UserSIDs) AS Targeted 
            ON Targeted.ResourceID = ComplianceStatus.ResourceID
            AND Targeted.CI_ID = ComplianceStatus.CI_ID
        WHERE CollectionMembers.CollectionID = @CollectionID
            AND IIF(Targeted.ResourceID IS NULL, 0, 1) IN (@Targeted) -- 筛选目标/非目标设备
            AND IIF(UpdateCIs.ArticleID = @ArticleID, 1, 0) = IIF(@ArticleID <> '', 1, 0)
        GROUP BY Systems.ResourceID
    ),
    HelperFunctionCheck AS (
        SELECT HelperFunctionExists = CASE WHEN OBJECT_ID('[dbo].[ufn_CM_GetNextMaintenanceWindow]') IS NOT NULL THEN 1 ELSE 0 END
    )
    SELECT
        Systems.ResourceID,
        HealthStates = (
            IIF(CombinedResources.IsClient != 1, POWER(1, 1), 0)
            + IIF(ClientSummary.ClientStateDescription IN ('Inactive/Pass', 'Inactive/Fail', 'Inactive/Unknown'), POWER(2, 1), 0)
            + IIF(ClientSummary.ClientStateDescription IN ('Active/Fail', 'Inactive/Fail'), POWER(4, 1), 0)
            + IIF(CombinedResources.ClientState != 0, POWER(8, 1), 0)
            + IIF(UpdateScan.LastErrorCode != 0, POWER(16, 1), 0)
            + IIF(UpdateScan.LastScanTime < DATEADD(dd, -14, CURRENT_TIMESTAMP), POWER(32, 1), 0)
            + IIF(ISNULL(Maintenance.NextServiceWindow, 0) = 0 AND (SELECT HelperFunctionExists FROM HelperFunctionCheck) = 1, POWER(64, 1), 0)
            + IIF(Maintenance.NextServiceWindow > DATEADD(dd, 30, CURRENT_TIMESTAMP), POWER(128, 1), 0)
            + IIF(Maintenance.NextServiceWindow < CURRENT_TIMESTAMP, POWER(256, 1), 0)
        ),
        Missing = ISNULL(UpdateInfo.Missing, IIF(CombinedResources.IsClient = 1, 0, NULL)),
        Device = (
            IIF(SystemNames.Resource_Names0 IS NOT NULL, UPPER(SystemNames.Resource_Names0),
                IIF(Systems.Full_Domain_Name0 IS NOT NULL, Systems.Name0 + '.' + Systems.Full_Domain_Name0, Systems.Name0)
            )
        ),
        OperatingSystem = (
            CASE
                WHEN OperatingSystem.Caption0 != '' THEN
                    CONCAT(
                        REPLACE(OperatingSystem.Caption0, 'Microsoft ', ''),
                        REPLACE(OperatingSystem.CSDVersion0, 'Service Pack ', ' SP')
                    )
                ELSE
                    CASE
                        WHEN CombinedResources.DeviceOS LIKE '%Workstation 6.1%' THEN 'Windows 7'
                        WHEN CombinedResources.DeviceOS LIKE '%Workstation 6.2%' THEN 'Windows 8'
                        WHEN CombinedResources.DeviceOS LIKE '%Workstation 6.3%' THEN 'Windows 8.1'
                        WHEN CombinedResources.DeviceOS LIKE '%Workstation 10.0%' THEN 'Windows 10'
                        WHEN CombinedResources.DeviceOS LIKE '%Server 6.0' THEN 'Windows Server 2008'
                        WHEN CombinedResources.DeviceOS LIKE '%Server 6.1' THEN 'Windows Server 2008R2'
                        WHEN CombinedResources.DeviceOS LIKE '%Server 6.2' THEN 'Windows Server 2012'
                        WHEN CombinedResources.DeviceOS LIKE '%Server 6.3' THEN 'Windows Server 2012 R2'
                        WHEN Systems.Operating_System_Name_And0 LIKE '%Server 10%' THEN
                            CASE WHEN CAST(REPLACE(Build01, '.', '') AS INTEGER) > 10017763 THEN 'Windows Server 2019' ELSE 'Windows Server 2016' END
                        ELSE Systems.Operating_System_Name_And0
                    END
            END
        ),
        LastBootTime = CONVERT(NVARCHAR(16), OperatingSystem.LastBootUpTime0, 120),
        PendingRestart = (
            CASE
                WHEN CombinedResources.IsClient = 0 OR CombinedResources.ClientState = 0 THEN NULL
                ELSE
                    STUFF(
                        REPLACE(
                            (SELECT '#!' + LTRIM(RTRIM(StateName)) AS [data()]
                             FROM ClientState
                             WHERE BitMask & CombinedResources.ClientState <> 0
                             FOR XML PATH('')),
                            ' #!', ', '
                        ),
                        1, 2, ''
                    )
            END
        ),
        ClientState = CASE CombinedResources.IsClient WHEN 1 THEN ClientSummary.ClientStateDescription ELSE 'Unmanaged' END,
        ClientVersion = CombinedResources.ClientVersion,
        LastUpdateScan = CONVERT(NVARCHAR(16), UpdateScan.LastScanTime, 120),
        LastScanLocation = NULLIF(UpdateScan.LastScanPackageLocation, ''),
        LastScanError = NULLIF(UpdateScan.LastErrorCode, 0),
        NextServiceWindow = IIF(CombinedResources.IsClient != 1, NULL, CONVERT(NVARCHAR(16), Maintenance.NextServiceWindow, 120))
    FROM fn_rbac_R_System(@UserSIDs) AS Systems
    JOIN fn_rbac_CombinedDeviceResources(@UserSIDs) AS CombinedResources 
        ON CombinedResources.MachineID = Systems.ResourceID
    LEFT JOIN fn_rbac_RA_System_ResourceNames(@UserSIDs) AS SystemNames 
        ON SystemNames.ResourceID = Systems.ResourceID
    LEFT JOIN fn_rbac_GS_OPERATING_SYSTEM(@UserSIDs) AS OperatingSystem 
        ON OperatingSystem.ResourceID = Systems.ResourceID
    LEFT JOIN fn_rbac_CH_ClientSummary(@UserSIDs) AS ClientSummary 
        ON ClientSummary.ResourceID = Systems.ResourceID
    LEFT JOIN fn_rbac_UpdateScanStatus(@UserSIDs) AS UpdateScan 
        ON UpdateScan.ResourceID = Systems.ResourceID
    LEFT JOIN MaintenanceInfo AS Maintenance 
        ON Maintenance.ResourceID = Systems.ResourceID
    LEFT JOIN UpdateInfo_CTE AS UpdateInfo 
        ON UpdateInfo.ResourceID = Systems.ResourceID
    JOIN fn_rbac_FullCollectionMembership(@UserSIDs) AS CollectionMembers 
        ON CollectionMembers.ResourceID = Systems.ResourceID
    CROSS JOIN HelperFunctionCheck
    WHERE CollectionMembers.CollectionID = @CollectionID
        AND (
            CASE -- 合规状态:0=不合规,1=合规,2=未知
                WHEN UpdateInfo.Missing = 0 OR (UpdateInfo.Missing IS NULL AND Systems.Client0 = 1) THEN 1
                WHEN UpdateInfo.Missing > 0 AND UpdateInfo.Missing IS NOT NULL THEN 0
                ELSE 2
            END
        ) IN (@Compliant)
)
GO

使用方式

-- 传入参数查询,效果与原查询完全一致
SELECT * FROM dbo.DeviceUpdateStatus(
    'Disabled',
    'SMS00001',
    2,
    'Tools',
    0,
    1,
    0,
    '',
    ''
)

方案2:创建存储过程生成物理表

如果需要将固定参数的结果持久化为物理表,可通过存储过程定期刷新数据。

存储过程代码

CREATE PROCEDURE dbo.RefreshDeviceUpdateStatusTable
    @UserSIDs NVARCHAR(10) = 'Disabled',
    @CollectionID NVARCHAR(10) = 'SMS00001',
    @Locale INT = 2,
    @Categories NVARCHAR(250) = 'Tools',
    @Compliant INT = 0,
    @Targeted INT = 1,
    @Superseded INT = 0,
    @ArticleID NVARCHAR(10) = '',
    @ExcludeArticleIDs NVARCHAR(250) = ''
AS
BEGIN
    SET NOCOUNT ON;

    -- 创建物理表(如果不存在)
    IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'DeviceUpdateStatus')
    BEGIN
        CREATE TABLE DeviceUpdateStatus (
            ResourceID INT,
            HealthStates INT,
            Missing INT,
            Device NVARCHAR(256),
            OperatingSystem NVARCHAR(256),
            LastBootTime NVARCHAR(16),
            PendingRestart NVARCHAR(256),
            ClientState NVARCHAR(100),
            ClientVersion NVARCHAR(50),
            LastUpdateScan NVARCHAR(16),
            LastScanLocation NVARCHAR(256),
            LastScanError INT,
            NextServiceWindow NVARCHAR(16)
        )
    END

    -- 清空现有数据
    TRUNCATE TABLE DeviceUpdateStatus;

    -- 插入新数据(保留原查询的变量和临时表逻辑)
    DECLARE @LCID AS INT = dbo.fn_LShortNameToLCID(@Locale);
    DECLARE @HelperFunctionExists AS INT = 0;

    IF OBJECT_ID('tempdb..#MaintenanceInfo', 'U') IS NOT NULL
        DROP TABLE #MaintenanceInfo;

    IF OBJECT_ID('[dbo].[ufn_CM_GetNextMaintenanceWindow]') IS NOT NULL
        SET @HelperFunctionExists = 1;

    DECLARE @HealthState TABLE (
        BitMask INT,
        StateName NVARCHAR(250)
    )

    INSERT INTO @HealthState (BitMask, StateName)
    VALUES
        (0,     'Healthy'),
        (1,   'Unmanaged'),
        (2,   'Inactive'),
        (4,   'Health Evaluation Failed'),
        (8,   'Pending Restart'),
        (16,  'Update Scan Failed'),
        (32,  'Update Scan Late'),
        (64,  'No Maintenance Window'),
        (128, 'Distant Maintenance Window'),
        (256, 'Expired Maintenance Window')

    DECLARE @ClientState TABLE (
        BitMask INT,
        StateName NVARCHAR(100)
    )

    INSERT INTO @ClientState (BitMask, StateName)
    VALUES
        (0, 'No Reboot'),
        (1, 'Configuration Manager'),
        (2, 'File Rename'),
        (4, 'Windows Update'),
        (8, 'Add or Remove Feature')

    CREATE TABLE #MaintenanceInfo (
        ResourceID INT,
        NextServiceWindow DATETIME
    )

    IF @HelperFunctionExists = 1
    BEGIN
        WITH Maintenance_CTE AS (
            SELECT
                CollectionMembers.ResourceID,
                NextServiceWindow.NextServiceWindow,
                RowNumber = DENSE_RANK() OVER (PARTITION BY ResourceID ORDER BY NextServiceWindow.NextServiceWindow)
            FROM vSMS_ServiceWindow AS ServiceWindow
            JOIN fn_rbac_FullCollectionMembership(@UserSIDs) AS CollectionMembers ON CollectionMembers.CollectionID = ServiceWindow.SiteID
            JOIN fn_rbac_Collection(@UserSIDs) AS Collections ON Collections.CollectionID = CollectionMembers.CollectionID
                AND Collections.CollectionType = 2
            CROSS APPLY ufn_CM_GetNextMaintenanceWindow(ServiceWindow.Schedules, ServiceWindow.RecurrenceType) AS NextServiceWindow
            WHERE NextServiceWindow.NextServiceWindow IS NOT NULL
                AND ServiceWindowType <> 5
        )
        INSERT INTO #MaintenanceInfo(ResourceID, NextServiceWindow)
        SELECT ResourceID, NextServiceWindow FROM Maintenance_CTE WHERE RowNumber = 1
    END

    ;WITH UpdateInfo_CTE
    AS (
        SELECT
            ResourceID = Systems.ResourceID,
            Missing = COUNT(*)
        FROM fn_rbac_R_System(@UserSIDs) AS Systems
        JOIN fn_rbac_UpdateComplianceStatus(@UserSIDs) AS ComplianceStatus ON ComplianceStatus.ResourceID = Systems.ResourceID
            AND ComplianceStatus.Status = 2
        JOIN fn_rbac_ClientCollectionMembers(@UserSIDs) AS CollectionMembers ON CollectionMembers.ResourceID = ComplianceStatus.ResourceID
        JOIN fn_rbac_UpdateInfo(@LCID, @UserSIDs) AS UpdateCIs ON UpdateCIs.CI_ID = ComplianceStatus.CI_ID
            AND UpdateCIs.IsSuperseded IN (@Superseded)
            AND UpdateCIs.CIType_ID IN (1, 8)
            AND UpdateCIs.ArticleID NOT IN (SELECT VALUE FROM STRING_SPLIT(@ExcludeArticleIDs, ','))
            AND UpdateCIs.Title NOT LIKE '[1-9][0-9][0-9][0-9]-[0-9][0-9]_Preview_of_%'
        JOIN fn_rbac_CICategoryInfo_All(@LCID, @UserSIDs) AS CICategory ON CICategory.CI_ID = ComplianceStatus.CI_ID
            AND CICategory.CategoryTypeName = 'UpdateClassification'
            AND CICategory.CategoryInstanceName IN (@Categories)
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:50:28