当数据具有 NULL 值时,如何使用 SQL 服务器中的 Pivot 将多行转换为多列的一行

How to convert multiple rows into one row with multiple columns using Pivot in SQL Server when data having NULL values

我有一个 table,我想在某些条件下从中获取数据。我正在通过以下查询获取数据。

SELECT track,
       ytd,
       weekno,
       [unit] 
FROM SMIrawdataFinal 
WHERE unit IS NOT NULL AND tracktype='focus' AND track='A' AND ytd IS NOT NULL

原table(数据)如下

track   ytd    weekno    unit
A      (Blank)   1        1
A      (Blank)   2        2
A      (Blank)   3        3
A        19      5        5
A      (Blank)   4        4

我在 sql 服务器中使用 PIVOT 获得了以下数据。我的问题是 如何删除空值并在一行中获取相同的数据。

autoId  track   ytd   col4   col3   col2    col1    
-------------------------------------------------
1         A   (Blank)  NULL    4      3       2  
2         A     19     5     NULL    NULL    NULL

下面是我的SQL查询:

SELECT * 
FROM (
    SELECT track,ytd,weekno,[unit]
    FROM SMIrawdataFinal
    WHERE album = 'XYZ' 
        AND unit IS NOT NULL
        AND tracktype='focus' 
        AND track='A' 
        AND ytd IS NOT NULL
    ) as s 
PIVOT(
    SUM(unit) 
    FOR weekno in ([5],[4],[3],[2])
)AS pivot1

如果您使用 SQL 服务器并且您喜欢将 col4col1 连接到一行,您可以这样实现:

SELECT p.track, p.ytd, 
    CONVERT(nvarchar(max),ISNULL(p.[5],0)) 
    + CONVERT(nvarchar(max),ISNULL(p.[4],0)) 
    + CONVERT(nvarchar(max),ISNULL(p.[3],0)) 
    + CONVERT(nvarchar(max),ISNULL(p.[2],0)) as asOneRow
FROM (
    SELECT track, ytd, weekno,[unit]
    FROM SMIrawdataFinal
    WHERE album = 'XYZ' 
        AND unit IS NOT NULL
        AND tracktype='focus' 
        AND track='A' 
        AND ytd IS NOT NULL
    ) as s 
PIVOT(
    SUM(unit) 
    FOR weekno in ([5],[4],[3],[2])
)AS p

如果你想把这些值加起来,你可以使用这个:

SELECT p.track, p.ytd, 
    SUM(ISNULL(p.[5],0)) as col4,
    SUM(ISNULL(p.[4],0)) as col3,
    SUM(ISNULL(p.[3],0)) as col2,
    SUM(ISNULL(p.[2],0)) as col1
FROM (
    SELECT track, ytd, weekno,[unit]
    FROM SMIrawdataFinal
    WHERE album = 'XYZ' 
        AND unit IS NOT NULL
        AND tracktype='focus' 
        AND track='A' 
        AND ytd IS NOT NULL
    ) as s 
PIVOT(
    SUM(unit) 
    FOR weekno in ([5],[4],[3],[2])
)AS p
GROUP BY p.track, p.ytd

根据您的示例数据和查询,我已将其设为单行,请在您的查询中添加 where 条件

declare @t table (track varchar(2),ytd int,weekno int,unit iNT)
insert into @t (track,ytd,weekno,unit)
values 
('A',NULL,1,1),
('A',NULL,2,2),
('A',NULL,3,3),
('A',19,5,5),
('A',NULL,4,4)

;with CTE AS (
SELECT * FROM (SELECT track,ytd,weekno,[unit]
FROM @t    )    as s PIVOT
(SUM(unit) FOR weekno in ([5],[4],[3],[2]))AS pivot1)
Select track,MAX(ytd)As YTD,MAX([5])AS [5],MAX([4])AS [4],MAX([3])AS [3],MAX([2])AS [2] from CTE 
GROUP BY track

动态版本

IF OBJECT_ID('tempdb..#t') IS NOT NULL 
DROP TABLE #t
GO

CREATE  table #t 
(track varchar(2),ytd int,weekno VARCHAR(5),unit INT)
insert into #t (track,ytd,weekno,unit)values 
('A',NULL,1,1),
('A',NULL,2,2),
('A',NULL,3,3),
('A',19,5,5),
('A',NULL,4,4)

DECLARE @statement NVARCHAR(max)
,@columns NVARCHAR(max)

SELECT @columns = ISNULL(@columns + ',', '') + N'[' + tbl.weekno + ']'
FROM (
   SELECT DISTINCT weekno
   FROM #t
   ) AS tbl

SELECT @statement = ' select track,
MAX(ytd)As YTD,
MAX([5])AS [5],
MAX([4])AS [4],
MAX([3])AS [3],
MAX([2])AS [2] from (
SELECT * FROM (SELECT track,ytd,weekno,[unit]
FROM #t    )    as s PIVOT
(SUM(unit) FOR weekno in(' + @columns + ')) as pvt)T
GROUP BY T.track'

EXEC sp_executesql @statement = @statement

将分组依据与 SUM 结合使用以获得所需的输出:

    SELECT track, 
    SUM(ISNULL(ytd, 0)) AS [ytd], 
    SUM(ISNULL([5], 0)) AS [5],
    SUM(ISNULL([4], 0)) AS [4],
    SUM(ISNULL([3], 0)) AS [3],
    SUM(ISNULL([2], 0)) AS [2]
    FROM (SELECT track,ytd,weekno,[unit]
    FROM SMIrawdataFinal where album = 'XYZ' 
            AND unit IS NOT NULL
            AND tracktype='focus' 
            AND track='A')    as s PIVOT
    (SUM(unit) FOR weekno in ([5],[4],[3],[2]))AS pivot1
    GROUP BY track

输出:

    track   | ytd   | 5 | 4  | 3    | 2
    --------------------------------
    A       | 19    | 5 | 4  | 3    | 2

我建议您在 select 上使用聚合并按轨道分组。

CREATE TABLE #t
(
    track  VARCHAR(10),
    ytd    INT,
    weekno INT,
    unit   INT
)
INSERT INTO #t VALUES    
('A',       NULL,   1,        1),
('A',       NULL,   2,        2),
('A',       NULL,   3,        3),
('A',       19,     5,        5),
('A',       NULL,   4,        4)

SELECT track, 
       MAX(COALESCE(ytd, 0)) [ytd], 
       MAX(COALESCE([5], 0)) [5],
       MAX(COALESCE([4], 0)) [4],
       MAX(COALESCE([3], 0)) [3],
       MAX(COALESCE([2], 0)) [2]
FROM (
SELECT track,
       ytd,
       weekno,
       [unit]
FROM #t 
WHERE unit IS NOT NULL AND track = 'A'
) as x 
PIVOT
(
    SUM(unit) 
    FOR weekno IN ([5],[4],[3],[2])
)AS piv
GROUP BY track

DROP TABLE #t

输出:

track   ytd 5   4   3   2
  A     19  5   4   3   2

SQL FIDDLE

我觉得还是好好想想这样做是否合理"merge"。为什么 weekno 5 到 2 的 YTD 都与 19 相同?如果 YTD 是 Year To Date,则不同的周数不应该相同。所以我的建议是放弃 YTD。

SELECT * 
FROM (
    SELECT track,/*ytd,*/ weekno,[unit]
    FROM SMIrawdataFinal
    WHERE album = 'XYZ' 
        AND unit IS NOT NULL
        AND tracktype='focus' 
        AND track='A' 
        /*AND ytd IS NOT NULL*/
    ) as s 
PIVOT(
    SUM(unit) 
    FOR weekno in ([5],[4],[3],[2])
)AS pivot1