基于数据之间的透视表求和

时间:2021-11-01 00:15:19

i really want to asking about pivot table in sql server. i have trying to do some query where the structure is like this.

我想问一下sql server中的pivot表。我试着在结构是这样的地方做一些查询。

DECLARE @cols AS NVARCHAR(MAX) 
DECLARE @query  AS NVARCHAR(MAX)
DECLARE @tanggal_awal date
DECLARE @tanggal_akhir date
DECLARE @print nvarchar(MAX)

CREATE TABLE #datatable  
(
    product_id int,
    product_date date,
    product_ammount int
)

SET @tanggal_awal = convert(date,'02-01-2017')
SET @tanggal_akhir = convert(date,'02-27-2017')



insert into #datatable (product_id,product_date,product_ammount) VALUES 
            (1,getdate(),100),
            (1,getdate(),900),
            (2,dateadd(DD,-1,getdate()),400),
            (3,DATEADD(DD,4,getdate()),300),
            (1,dateadd(DD,4,getdate()),200),
            (2,dateadd(DD,2,getdate()),700),
            (4,dateadd(DD,-3,getdate()),1000)

--SELECT * FROM @datatable

;WITH CTE (datelist,maxdate) AS 
(
    select min(@tanggal_awal) datelist, max(product_date) maxdate
    from #datatable
    union all
    select dateadd(dd, 1, datelist), @tanggal_akhir
    from cte
    where datelist < maxdate
) SELECT c.datelist 
    into #temp
    from cte c

select @cols =  STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), datelist, 120)) 
                from #temp
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
                ,1,1,'')

--SELECT d.datelist, b.product_id, SUM(b.product_ammount) 
--  FROM #temp d left join #datatable b on 
--  d.datelist between @tanggal_awal and @tanggal_akhir
--  AND d.datelist = b.product_date
--  GROUP BY b.product_id, d.datelist

--select b.product_id, d.datelist, 
--                sum(b.product_ammount) PivotDate
--                from #datatable b
--                left join #temp d
--                on d.datelist between @tanggal_awal and @tanggal_akhir
--              and d.datelist = b.product_date
--group by b.product_id, d.datelist
--order by b.product_id


SET @query = 'SELECT product_id, '+@cols+' FROM 
             (
                select b.product_id, d.datelist, convert(CHAR(10), datelist, 120) PivotDate
                from #datatable b
                left join #temp d
                on d.datelist between @tanggal_awal and @tanggal_akhir
                and d.datelist = b.product_date

            ) x
            pivot 
            (
                count(datelist)
                for PivotDate in (' +@cols+ ')
            ) p'


EXECUTE sp_executesql @query ,N'@tanggal_awal DATE, @tanggal_akhir DATE', @tanggal_awal,@tanggal_akhir
GO
drop table #temp
go
drop table #datatable

the result from this query is mostly count of the 'product_id' in the respective date. however, i want to get sum of the total based on product_ammount like this.

该查询的结果主要是“product_id”在相应的日期内的计数。但是,我想基于product_ammount得到总数的总和。

-------------------------------------
|product_id| 2017-01-02 | 2017-02-02|
-------------------------------------
|1         | 0          | 1000      |
-------------------------------------
|2         | 900        | 0         |
-------------------------------------
|3         | 700        | 0         |
-------------------------------------

can anyone give me the best way to handle join and pivot together, especially for this case ? thank you very much.

有没有人能给我最好的方式来处理连接和旋转,特别是对于这个例子?非常感谢。

--Update after the query from Shakeer Mirza, the result is like this.

——在Shakeer Mirza查询后更新,结果如下。

基于数据之间的透视表求和

can we group it ?

我们可以分组吗?

3 个解决方案

#1


2  

Try this below. I think you need change your Pivot to SUM of product_ammount and the qry X to have product_ammount in Select

试试这个。我认为您需要将Pivot改为product_ammount和qry X的和,以便在Select中包含product_ammount

SET @query = 'SELECT product_id, '+@cols+' FROM 
             (

                select b.product_id,  convert(CHAR(10), datelist, 120) PivotDate,  product_ammount  
                from #datatable b
                left join #temp d
                on d.datelist between  @tanggal_awal and @tanggal_akhir
                and d.datelist = b.product_date


            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'


EXECUTE sp_executesql @query ,N'@tanggal_awal DATE, @tanggal_akhir DATE', @tanggal_awal,@tanggal_akhir
GO
drop table #temp
go
drop table #datatable

Update: To replace Null

更新:替代Null

DECLARE @COLS_ISNULL VARCHAR(MAX)='';

SELECT @COLS_ISNULL = @COLS_ISNULL +COLS_ISNULL+',' FROM (
SELECT distinct   'ISNULL('+QUOTENAME(convert(CHAR(10), datelist, 120))+',0) 'as COLS_ISNULL
                from #temp)A
--to remove last comma.
SELECT @COLS_ISNULL = SUBSTRING (@COLS_ISNULL,1,LEN(@COLS_ISNULL)-1)

And replace the above @COLS_ISNULL in Select of your @query.

并在Select of your @query中替换上面的@COLS_ISNULL。

SET @query = 'SELECT product_id, '+@COLS_ISNULL+' FROM 
             (

                select b.product_id,  convert(CHAR(10), datelist, 120) PivotDate,  product_ammount  
                from #datatable b
                left join #temp d
                on d.datelist between  @tanggal_awal and @tanggal_akhir
                and d.datelist = b.product_date


            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'

From comments:

评论:

This is the Output from my SSMS

这是SSMS的输出

基于数据之间的透视表求和

#2


1  

Your query can be simplified to:

你的查询可简化为:

SET @query = 
    'SELECT product_id, '+@cols+' FROM 
     (
         select b.product_id, b.product_ammount, 
                convert(CHAR(10), product_date, 120) PivotDate
         from #datatable b
         where product_date between @tanggal_awal and @tanggal_akhir                   
     ) x
     pivot 
     (
         sum(product_ammount)
         for PivotDate in (' +@cols+ ')
     ) p'

You don't have to LEFT JOIN to #temp since for clause in the pivot operation is what really returns a list of all dates.

您不必将JOIN保留为#temp,因为pivot操作中的for子句实际上返回所有日期的列表。

#3


1  

based on Shakeer Mirza and Giorgos Betos Answer for this question, finally i have solved this problem. this is the full query for this problem

基于Shakeer Mirza和Giorgos对这个问题的回答,最终我解决了这个问题。这是对这个问题的完整查询

DECLARE @cols AS NVARCHAR(MAX)
DECLARE @colswithNoNulls AS NVARCHAR(MAX)
DECLARE @query  AS NVARCHAR(MAX)
DECLARE @tanggal_awal date
DECLARE @tanggal_akhir date
DECLARE @print nvarchar(MAX)

CREATE TABLE #datatable  
(
    product_id int,
    product_date date,
    product_ammount int
)

SET @tanggal_awal = convert(date,'02-01-2017')
SET @tanggal_akhir = convert(date,'02-27-2017')



insert into #datatable (product_id,product_date,product_ammount) VALUES 
            (1,getdate(),100),
            (1,getdate(),900),
            (2,dateadd(DD,-1,getdate()),400),
            (3,DATEADD(DD,4,getdate()),300),
            (1,dateadd(DD,4,getdate()),200),
            (2,dateadd(DD,2,getdate()),700),
            (4,dateadd(DD,-3,getdate()),1000)


;WITH CTE (datelist,maxdate) AS 
(
    select min(@tanggal_awal) datelist, max(product_date) maxdate
    from #datatable
    union all
    select dateadd(dd, 1, datelist), @tanggal_akhir
    from cte
    where datelist < maxdate
) SELECT c.datelist 
    into #temp
    from cte c

select @cols =  STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), datelist, 120)) 
                from #temp
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
                ,1,1,'')

select @colswithNoNulls =   STUFF((SELECT distinct ',ISNULL(' + QUOTENAME(convert(CHAR(10), datelist, 120)) +',''0'') '+ QUOTENAME(convert(CHAR(10), datelist, 120)) 
                            from #temp
                            FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)') 
                            ,1,1,'')

SET @query = 
            'SELECT product_id, '+ @colswithNoNulls+' FROM 
             (
                select b.product_id, coalesce(b.product_ammount,0) as product_ammount, 
                       convert(CHAR(10), product_date, 120) PivotDate
                from #datatable b
                where product_date between @tanggal_awal and @tanggal_akhir                                
            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'            


EXECUTE sp_executesql @query ,N'@tanggal_awal DATE, @tanggal_akhir DATE', @tanggal_awal,@tanggal_akhir
GO
drop table #temp
go
drop table #datatable

the idea is from How to replace (null) values with 0 output in PIVOT. The idea itself is to make two different cols, one for only the cols and another one with ISNULL. Hopefully this problem can solve a lot of problem in the near future :)

其思想是从如何将(null)值替换为PIVOT中的0输出。这个想法本身就是制作两个不同的cols,一个用于cols,另一个用于ISNULL。希望这个问题能在不久的将来解决很多问题。

#1


2  

Try this below. I think you need change your Pivot to SUM of product_ammount and the qry X to have product_ammount in Select

试试这个。我认为您需要将Pivot改为product_ammount和qry X的和,以便在Select中包含product_ammount

SET @query = 'SELECT product_id, '+@cols+' FROM 
             (

                select b.product_id,  convert(CHAR(10), datelist, 120) PivotDate,  product_ammount  
                from #datatable b
                left join #temp d
                on d.datelist between  @tanggal_awal and @tanggal_akhir
                and d.datelist = b.product_date


            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'


EXECUTE sp_executesql @query ,N'@tanggal_awal DATE, @tanggal_akhir DATE', @tanggal_awal,@tanggal_akhir
GO
drop table #temp
go
drop table #datatable

Update: To replace Null

更新:替代Null

DECLARE @COLS_ISNULL VARCHAR(MAX)='';

SELECT @COLS_ISNULL = @COLS_ISNULL +COLS_ISNULL+',' FROM (
SELECT distinct   'ISNULL('+QUOTENAME(convert(CHAR(10), datelist, 120))+',0) 'as COLS_ISNULL
                from #temp)A
--to remove last comma.
SELECT @COLS_ISNULL = SUBSTRING (@COLS_ISNULL,1,LEN(@COLS_ISNULL)-1)

And replace the above @COLS_ISNULL in Select of your @query.

并在Select of your @query中替换上面的@COLS_ISNULL。

SET @query = 'SELECT product_id, '+@COLS_ISNULL+' FROM 
             (

                select b.product_id,  convert(CHAR(10), datelist, 120) PivotDate,  product_ammount  
                from #datatable b
                left join #temp d
                on d.datelist between  @tanggal_awal and @tanggal_akhir
                and d.datelist = b.product_date


            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'

From comments:

评论:

This is the Output from my SSMS

这是SSMS的输出

基于数据之间的透视表求和

#2


1  

Your query can be simplified to:

你的查询可简化为:

SET @query = 
    'SELECT product_id, '+@cols+' FROM 
     (
         select b.product_id, b.product_ammount, 
                convert(CHAR(10), product_date, 120) PivotDate
         from #datatable b
         where product_date between @tanggal_awal and @tanggal_akhir                   
     ) x
     pivot 
     (
         sum(product_ammount)
         for PivotDate in (' +@cols+ ')
     ) p'

You don't have to LEFT JOIN to #temp since for clause in the pivot operation is what really returns a list of all dates.

您不必将JOIN保留为#temp,因为pivot操作中的for子句实际上返回所有日期的列表。

#3


1  

based on Shakeer Mirza and Giorgos Betos Answer for this question, finally i have solved this problem. this is the full query for this problem

基于Shakeer Mirza和Giorgos对这个问题的回答,最终我解决了这个问题。这是对这个问题的完整查询

DECLARE @cols AS NVARCHAR(MAX)
DECLARE @colswithNoNulls AS NVARCHAR(MAX)
DECLARE @query  AS NVARCHAR(MAX)
DECLARE @tanggal_awal date
DECLARE @tanggal_akhir date
DECLARE @print nvarchar(MAX)

CREATE TABLE #datatable  
(
    product_id int,
    product_date date,
    product_ammount int
)

SET @tanggal_awal = convert(date,'02-01-2017')
SET @tanggal_akhir = convert(date,'02-27-2017')



insert into #datatable (product_id,product_date,product_ammount) VALUES 
            (1,getdate(),100),
            (1,getdate(),900),
            (2,dateadd(DD,-1,getdate()),400),
            (3,DATEADD(DD,4,getdate()),300),
            (1,dateadd(DD,4,getdate()),200),
            (2,dateadd(DD,2,getdate()),700),
            (4,dateadd(DD,-3,getdate()),1000)


;WITH CTE (datelist,maxdate) AS 
(
    select min(@tanggal_awal) datelist, max(product_date) maxdate
    from #datatable
    union all
    select dateadd(dd, 1, datelist), @tanggal_akhir
    from cte
    where datelist < maxdate
) SELECT c.datelist 
    into #temp
    from cte c

select @cols =  STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), datelist, 120)) 
                from #temp
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
                ,1,1,'')

select @colswithNoNulls =   STUFF((SELECT distinct ',ISNULL(' + QUOTENAME(convert(CHAR(10), datelist, 120)) +',''0'') '+ QUOTENAME(convert(CHAR(10), datelist, 120)) 
                            from #temp
                            FOR XML PATH(''), TYPE
                            ).value('.', 'NVARCHAR(MAX)') 
                            ,1,1,'')

SET @query = 
            'SELECT product_id, '+ @colswithNoNulls+' FROM 
             (
                select b.product_id, coalesce(b.product_ammount,0) as product_ammount, 
                       convert(CHAR(10), product_date, 120) PivotDate
                from #datatable b
                where product_date between @tanggal_awal and @tanggal_akhir                                
            ) x
            pivot 
            (
                sum(product_ammount)
                for PivotDate in (' +@cols+ ')
            ) p'            


EXECUTE sp_executesql @query ,N'@tanggal_awal DATE, @tanggal_akhir DATE', @tanggal_awal,@tanggal_akhir
GO
drop table #temp
go
drop table #datatable

the idea is from How to replace (null) values with 0 output in PIVOT. The idea itself is to make two different cols, one for only the cols and another one with ISNULL. Hopefully this problem can solve a lot of problem in the near future :)

其思想是从如何将(null)值替换为PIVOT中的0输出。这个想法本身就是制作两个不同的cols,一个用于cols,另一个用于ISNULL。希望这个问题能在不久的将来解决很多问题。