简体   繁体   中英

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

I have a table from which I want to get data under some conditions. I am getting data with below query.

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

Original table (data) is like below.

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

I got below data using PIVOT in sql server. My problem is how can I remove null values and get the same data in one single row.

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

Below is my SQL Query:

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

Use a group by with SUM to get the desired output:

    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

Output:

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

If your using SQL Server and you like to concatenate the col4 to col1 to one row, you can achieve this like that:

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

If you want to sum those values up you can use this:

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

basing on your sample data and query i have made this into single row and please add where conditions in your query

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

DYNAMIC VERSION

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

I suggest you to use aggregates on select and group by track.

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

OUTPUT:

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

SQL FIDDLE

I think it is better to think whether it is reasonable to doing this "merge". Why weekno 5 to 2 all have same YTD as 19? If YTD is Year To Date, it should not be same for different week numbers. So my suggestion is to drop 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM