2017-02-08 2 views
3

난 정말 SQL Server의 피벗 테이블에 대해 물어보고 싶어요. 구조가 이와 같은 경우 쿼리를 수행하려고합니다.피벗 테이블 합계 날짜 사이에

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, '[email protected]+' 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 (' [email protected]+ ') 
      ) p' 


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

이 쿼리의 결과는 대부분 해당 날짜의 'product_id'입니다. 그러나, 나는이 같은 product_ammount를 기반으로 합계의 합계를 얻고 싶습니다.

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

아무에게도이 경우 특히 조인과 피벗을 함께 처리하는 가장 좋은 방법을 제공 할 수 있습니까? 고마워요.

- 업데이트 Shakeer Mirza에서 쿼리 한 결과는 다음과 같습니다.

enter image description here

우리 그룹이 할 수있는?

답변

2

아래에서보십시오. 이

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) 

널 교체를 선택 위의 @COLS_ISNULL를 교체하려면 : 나는 당신이

SET @query = 'SELECT product_id, '[email protected]+' 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 (' [email protected]+ ') 
      ) p' 


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

업데이트 선택에 product_ammount을 가지고 product_ammountSUM과 QRY X로 피벗을 변경할 필요가 있다고 생각 당신의 @query. 댓글에서

SET @query = 'SELECT product_id, '[email protected]_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 (' [email protected]+ ') 
      ) p' 

는 :

이 내 SSMS에서 출력

enter image description here

+0

그것은 작동합니다 :), 정말 고마워.하지만 결과는 정말 좋지 않아. –

+0

환영합니다 :) @FarisFajar –

+0

@mirza, 결과가 그룹화되지 않았으므로 그룹화하는 방법은 무엇입니까? –

1

귀하의 쿼리를 단순화 할 수 있습니다

SET @query = 
    'SELECT product_id, '[email protected]+' 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 (' [email protected]+ ') 
    ) p' 

당신은하지 않습니다해야합니다.~ #temppivotfor 절이 실제로 모든 날짜의 목록을 반환하기 때문에 작동합니다.

+0

나는 당신의 대답이 가장 완벽한 것 같아요. 고마워요 :), btw, null을 제거하려면 coalesce (x, 0) 같은 것을 넣어야합니까? –

1

Shakeer Mirza 및 Giorgos Betos에 기반이 질문에 대한 답변은 마침내이 문제를 해결했습니다. 이 아이디어는 How to replace (null) values with 0 output in PIVOT에서이 문제에

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 (' [email protected]+ ') 
      ) p'    


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

의 전체 쿼리입니다. 아이디어 자체는 두 개의 서로 다른 열을 만드는 것인데 하나는 열과 ISNULL을 가진 것입니다. 잘하면이 문제는 가까운 장래에 많은 문제를 해결할 수 있습니다 :)

+0

마침내 얻었습니다. :) –