sqlserver. Нужно заменить NULL на 0 в результирующем наборе после PIVOT

При добавлении новых строк с новыми месяцами они автоматически прилетают и в запрос с PIVOT. Подскажите плз, как заменить NULL'ы.

create table #gsTestOrdering
(id int identity(1,1), company nvarchar(10), OrderAmount int, OrderDate datetime);

insert into #gsTestOrdering
values
('Газпром',180000,'2017-01-01'),('Роснефть',320000,'2017-01-02'),
('Альфа',80000,'2017-01-01'),('Альфа',45000,'2017-02-05'),
('Роснефть',480,'2017-02-01'),('Газпром',1900,'2017-01-01'),
('Альфа',1200,'2017-01-01'),('Газпром',1550000,'2017-02-01'),
('Роснефть',50060,'2017-01-01'),('Газпром',90000,'2017-01-01'),
('Роснефть',70000,'2017-02-01'),('Газпром',11000,'2017-03-01'),
('Роснефть',9000,'2017-03-01'),('Газпром',150000,'2017-01-01'),
('Альфа',50000,'2017-03-01'),('Роснефть',60000,'2017-03-01'),
('Роснефть',9000,'2017-01-01'),('Газпром',15000,'2017-03-01'),
('Альфа',10000,'2017-02-01'),('Роснефть',60000,'2017-02-01'),
('Газпром',180000,'2017-04-01'),('Роснефть',320000,'2017-05-02')
--,('Альфа',10000,'2017-11-01'),('Роснефть',60000,'2017-08-01')   --добавление новых месяцев
--,('Газпром',180000,'2017-12-01'),('Роснефть',320000,'2017-07-02')
;


declare @months table ([mon] varchar(max),
                       num int identity (1,1))
insert into @months ([mon])
select distinct datename(mm, orderdate) as [mon] 
from #gsTestOrdering

declare @val nvarchar(max);

set @val = 
(select stuff((select ',' + mon
               from @months
               for xml path('')
              ), 1, 1, '')
);

select @val

declare @select nvarchar(max);

set @select = 'select company, ' + @val +
' from 
    (
        select company, sum(orderamount) as sumorder, datename(mm, orderdate) as [mon]
        from #gsTestOrdering
        group by company, datename(mm, orderdate)
    ) t
    pivot(sum(sumorder)
            for [mon]
                IN (' + @val + ')
            ) as d';

exec (@select)

--delete from #gsTestOrdering
--where orderdate in ('2017-11-01', '2017-08-01', '2017-12-01', '2017-07-02')  --удаление лишних месяцев

drop table if exists #gsTestOrdering;

Заранее спасибо за помощь.


Ответы (2 шт):

Автор решения: Yitzhak Khabinsky

Попробуйте следующее решение. Оно будет работать на SQL Server 2017 и более поздних версиях.

SQL

USE tempdb;
GO

DROP TABLE IF EXISTS #gsTestOrdering;

CREATE table #gsTestOrdering
(id int identity(1,1), company nvarchar(10), OrderAmount int, OrderDate datetime);

insert into #gsTestOrdering
values
(N'Газпром',180000,'2017-01-01'),(N'Роснефть',320000,'2017-01-02'),
(N'Альфа',80000,'2017-01-01'),(N'Альфа',45000,'2017-02-05'),
(N'Роснефть',480,'2017-02-01'),(N'Газпром',1900,'2017-01-01'),
(N'Альфа',1200,'2017-01-01'),(N'Газпром',1550000,'2017-02-01'),
(N'Роснефть',50060,'2017-01-01'),(N'Газпром',90000,'2017-01-01'),
(N'Роснефть',70000,'2017-02-01'),(N'Газпром',11000,'2017-03-01'),
(N'Роснефть',9000,'2017-03-01'),(N'Газпром',150000,'2017-01-01'),
(N'Альфа',50000,'2017-03-01'),(N'Роснефть',60000,'2017-03-01'),
(N'Роснефть',9000,'2017-01-01'),(N'Газпром',15000,'2017-03-01'),
(N'Альфа',10000,'2017-02-01'),(N'Роснефть',60000,'2017-02-01'),
(N'Газпром',180000,'2017-04-01'),(N'Роснефть',320000,'2017-05-02');

declare @months table ([mon] varchar(max), num int identity (1,1));
insert into @months ([mon])
select distinct datename(mm, orderdate) as [mon] 
from #gsTestOrdering;

declare @val nvarchar(max);

set @val = 
(select stuff((select ',' + mon
               from @months
               for xml path('')
              ), 1, 1, '')
);

SELECT @val;

DECLARE @col_list NVARCHAR(MAX);

SET @col_list = (SELECT STRING_AGG('COALESCE(' + value + ',0) AS ' + value, ',')
FROM STRING_SPLIT(@val, ','));

declare @select nvarchar(max);

set @select = 'select company, ' + @col_list +
' from 
    (
        select company, sum(orderamount) as sumorder, datename(mm, orderdate) as [mon]
        from #gsTestOrdering
        group by company, datename(mm, orderdate)
    ) t
    pivot(sum(sumorder)
            for [mon]
                IN (' + @val + ')
            ) as d';

PRINT @select;
EXEC (@select);
→ Ссылка
Автор решения: Skate_banana
create table #gsTestOrdering
(id int identity(1,1), company nvarchar(10), OrderAmount int, OrderDate datetime);

insert into #gsTestOrdering
values
('Газпром',180000,'2017-01-01'),('Роснефть',320000,'2017-01-02'),
('Альфа',80000,'2017-01-01'),('Альфа',45000,'2017-02-05'),
('Роснефть',480,'2017-02-01'),('Газпром',1900,'2017-01-01'),
('Альфа',1200,'2017-01-01'),('Газпром',1550000,'2017-02-01'),
('Роснефть',50060,'2017-01-01'),('Газпром',90000,'2017-01-01'),
('Роснефть',70000,'2017-02-01'),('Газпром',11000,'2017-03-01'),
('Роснефть',9000,'2017-03-01'),('Газпром',150000,'2017-01-01'),
('Альфа',50000,'2017-03-01'),('Роснефть',60000,'2017-03-01'),
('Роснефть',9000,'2017-01-01'),('Газпром',15000,'2017-03-01'),
('Альфа',10000,'2017-02-01'),('Роснефть',60000,'2017-02-01'),
('Газпром',180000,'2017-04-01'),('Роснефть',320000,'2017-05-02')
--,('Альфа',10000,'2017-11-01'),('Роснефть',60000,'2017-08-01')   --добавление новых месяцев
--,('Газпром',180000,'2017-12-01'),('Роснефть',320000,'2017-07-02')
;


declare @months table ([mon] varchar(max),
                       num int identity (1,1))
insert into @months ([mon])
select distinct datename(mm, orderdate) as [mon] 
from #gsTestOrdering

declare @val nvarchar(max);
declare @val1 nvarchar(max);

set @val = 
(select stuff((select ',' + mon
               from @months
               for xml path('')
              ), 1, 1, '')
);

set @val1 = 
(select stuff((select ', isnull(' + mon + ', ''0'') as '+ mon
               from @months
               for xml path('')
              ), 1, 1, '')
);

select @val;
select @val1;

declare @select nvarchar(max);

set @select = 'select company, ' + @val1 +
' from 
    (
        select company, sum(orderamount) as sumorder, datename(mm, orderdate) as [mon]
        from #gsTestOrdering
        group by company, datename(mm, orderdate)
    ) t
    pivot(sum(sumorder)
            for [mon]
                IN (' + @val + ')
            ) as d';

exec (@select)

----delete from #gsTestOrdering
----where orderdate in ('2017-11-01', '2017-08-01', '2017-12-01', '2017-07-02')  --удаление лишних месяцев

drop table if exists #gsTestOrdering;
→ Ссылка