使用Pivot的动态列的SQL查询

时间:2017-09-19 18:35:49

标签: sql sql-server pivot sccm

我知道这个主题无处不在,但我无法让它正常工作。它可能非常简单。

以下是基本查询后的数据示例:

-----------------------------------
|Site| Model              | Count |
-----------------------------------
AAA   ProLiant DL380 G7     1
AAA   OptiPlex 790          500
BBB   OptiPlex 780          80
CCC   OptiPlex 790          23
...

我想要的是列名称是动态的:

--------------------------------------------------------
|Site| ProLiant DL380 G7 | OptiPlex 790 | OptiPlex 780 |...
--------------------------------------------------------
AAA             1               500            0
BBB             0               0              80
CCC             0               23             0

根据我的研究,这是我迄今为止编写的代码:

DECLARE 
    @cols AS NVARCHAR(MAX),
    @query AS NVARCHAR(MAX)

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Model)
     FROM
    (
        SELECT IIF(COMP.Manufacturer0 LIKE '%lenovo%',PRD.Version0,COMP.Model0) AS Model
        FROM v_GS_COMPUTER_SYSTEM COMP
        JOIN v_GS_COMPUTER_SYSTEM_PRODUCT PRD ON COMP.ResourceID=PRD.ResourceID
    ) AS inner_tbl
    FOR XML PATH(''),Type).value('.', 'NVARCHAR(MAX)'),1,1,'')

SET @query = 'SELECT Site, ' + @cols + ' FROM
    (
        SELECT Site, Model, COUNT(Model) AS Count FROM
        (
            SELECT UPPER(Substring(SYS.Name0,2,3)) AS Site, IIF(COMP.Manufacturer0 LIKE ''%lenovo%'',PRD.Version0,COMP.Model0) AS Model
            FROM v_GS_System SYS
            JOIN v_GS_COMPUTER_SYSTEM COMP ON SYS.ResourceID=COMP.ResourceID
            JOIN v_GS_COMPUTER_SYSTEM_PRODUCT PRD ON SYS.ResourceID=PRD.ResourceID
        ) AS inner_tbl2
        GROUP BY Site, Model
    ) AS inner_tbl1
    PIVOT
    (
        max(Model)
        FOR Site in ' + @cols + ')
    ) AS piv

'

EXECUTE(@query)

当我运行查询时,出现语法错误。

3 个答案:

答案 0 :(得分:3)

使用Dynamic Sql

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

CREATE TABLE #TempData (
    [Site] CHAR(3) NOT NULL,
    Model VARCHAR(30) NOT NULL,
    SomeCount INT NOT NULL DEFAULT(0)
    );
INSERT #TempData (Site, Model, SomeCount) VALUES
    ('AAA', 'ProLiant DL380 G7', 1), 
    ('AAA', 'OptiPlex 790', 500), 
    ('BBB', 'OptiPlex 780', 80),
    ('CCC', 'OptiPlex 790', 23);

Declare @DynamicCol nvarchar(max),@DynamicColNull nvarchar(max)
        ,@Sql nvarchar(max)

SELECT @DynamicColNull=STUFF((SELECT DISTINCT ', '+'ISNULL('+QUOTENAME(Model),','+'''0'''+') As '+QUOTENAME(Model)
                        FROM #TempData FOR XML PATH ('')),1,2,'')

SELECT @DynamicCol=STUFF((SELECT DISTINCT ', '+QUOTENAME(Model) FROM #TempData FOR XML PATH ('')),1,2,'')

SET @Sql='SELECT [Site], '+@DynamicColNull+' From
            (   
            SELECT * from #TempData
            )
            AS Src
            PIVOT
            (
            MAX(SomeCount) FOR [Model] IN ('+@DynamicCol+')
            )AS Pvt'
PRINT @Sql
EXEC(@Sql)

结果

Site    OptiPlex 780    OptiPlex 790    ProLiant DL380 G7
AAA         0               500             1
BBB         80              0               0
CCC         0               23              0

答案 1 :(得分:0)

试一试......

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

CREATE TABLE #TestData (
    [Site] CHAR(3) NOT NULL,
    Model VARCHAR(30) NOT NULL,
    SomeCount INT NOT NULL DEFAULT(0)
    );
INSERT #TestData (Site, Model, SomeCount) VALUES
    ('AAA', 'ProLiant DL380 G7', 1), 
    ('AAA', 'OptiPlex 790', 500), 
    ('BBB', 'OptiPlex 780', 80),
    ('CCC', 'OptiPlex 790', 23);

--==========================================================

DECLARE 
    @PivotColumns NVARCHAR(4000),
    @sql NVARCHAR(4000),
    @DeBug BIT = 0;

SELECT 
    @PivotColumns = CONCAT(@PivotColumns, N',
    ', QUOTENAME(td.Model), N' = SUM(CASE WHEN td.Model = ', QUOTENAME(td.Model, ''''), N' THEN td.SomeCount END)') 
FROM
    #TestData td
GROUP BY
    td.Model
-- ORDER BY ??? if you want the columns in a specific ordinal position.
;

SET @sql = CONCAT(N'
SELECT 
    td.[Site]',
    @PivotColumns, N'
FROM
    #TestData td
GROUP BY
    td.[Site];');

IF @DeBug = 1
BEGIN 
    PRINT (@sql);
END;
ELSE 
BEGIN 
    EXEC sys.sp_executesql @sql;
END;

结果...

Site OptiPlex 780 OptiPlex 790 ProLiant DL380 G7
---- ------------ ------------ -----------------
AAA  NULL         500          1
BBB  80           NULL         NULL
CCC  NULL         23           NULL

答案 2 :(得分:0)

从您的查询

PIVOT
(
    max(Model)
    FOR Site in ' + @cols + ')
) AS piv

您应该使用Count函数中的MAX()列和Model部分中的FOR...IN列。这是因为您的新值将是Count,而您的新列将来自Model

中的值