动态数据透视查询,动态日期为SQL Server中的列标题

时间:2017-01-18 05:35:18

标签: sql sql-server

这是SQL Server的实际结果集

+-----------+--------+------------------+
| Dates     | Orders | Cancelled Orders |
+-----------+--------+------------------+
|2016-01-17 |  100   |       50         |             
|2016-01-18 |  120   |       20         |                
|2016-01-20 |  150   |       30         |    
+-----------+--------+------------------+

我需要转动表格,如下所示

+----------+------------+------------+------------+
|Dates     | 2016-01-17 | 2016-01-18 | 2016-01-19 |
+----------+------------+------------+------------+
|Orders    |    100     | 120        |  150       | 
+----------+------------+------------+------------+
|Cancelled |            |            |            |
|Orders    |     50     |  20        |   30       |
+----------+------------+------------+------------+

任何人都可以在撰写查询时给我建议吗?这里的日期必须是动态的。

4 个答案:

答案 0 :(得分:2)

试试这个查询......它会帮助你

select * into #tempp from(

select '2016-01-17' as DATES,100 ORDERS,50 CANCELED_ORDERS
UNION ALL
SELECT '2016-01-18',120,20
UNION ALL
SELECT '2016-01-20',150,30
)AS A

--SELECT * FROM #tempp

declare @pivotcols nvarchar(max),@unpivotcols nvarchar(max),@SQLQUERY NVARCHAR(MAX)
select @pivotcols=stuff((select ','+quotename(dates) from #tempp for xml path('')),1,1,'')
--select @pivotcols

select @unpivotcols=stuff((select ','+name from tempdb.sys.columns where object_id =
object_id('tempdb..#tempp') and name<>'DATES' for xml path('')),1,1,'')
--select @unpivotcols

SET @SQLQUERY=N'select * from (
SELECT * FROM #tempp
)as a
unpivot (AMOUNTS FOR Dates  in ('+@unpivotcols+N') 
) AS UNPI
PIVOT (MAX(AMOUNTS) FOR DATES IN ('+@pivotcols+N')
)AS A'

PRINT @SQLQUERY

EXEC SP_EXECUTESQL @SQLQUERY

输出就像。

    +-----------------+------------+------------+------------+
    |      Dates       | 2016-01-17 | 2016-01-18 | 2016-01-20|
    +-----------------+------------+------------+------------+
    | CANCELED_ORDERS |         50 |         20 |         30 |
    | ORDERS          |        100 |        120 |        150 |
    +-----------------+------------+------------+------------+

答案 1 :(得分:0)

您需要分两部分来解决问题。

在第一部分中,使用SQL的 coalesce 函数连接您的日期和枢轴查询相同,但参数除外。

在第二部分中,使用动态SQL进行主数据透视查询,而不是静态日期传递保存日期的变量(您在第一部分中已经获得)

以下是我在项目中运行的查询,您必须替换其中的表逻辑。

        Create Table #Temp (Salesdays int)

    Insert into #Temp (Salesdays)values(7) 
    Insert into #Temp (Salesdays)values(14) 
    Insert into #Temp (Salesdays)values(30) 
    Insert into #Temp (Salesdays)values(90) 
    Insert into #Temp (Salesdays)values(180) 
    Insert into #Temp (Salesdays)values(365) 


    DECLARE @PivotColumns nVARCHAR(MAX)
    SELECT @PivotColumns = COALESCE(@PivotColumns + ',[' + cast([Salesdays] as varchar(5))+']', '['+cast([Salesdays] as varchar(5))+']') 
    FROM #Temp
    Print @PivotColumns


    Declare @SQLQuery nVarchar(max)=N'Select
    SellerSKU, 
    MarketPlaceCode,
    isnull([7],0) as   [SalesData_7],
    isnull([14],0) as  [SalesData_14],
    isnull([30],0) as  [SalesData_30],
    isnull([90],0) as  [SalesData_90],
    isnull([180],0) as [SalesData_180], 
    isnull([365],0) as [SalesData_365] 
    from
    (
    Select 
    SellerSKU,
    MPDetail.MarketPlaceCode,
    Sum(QuantityShipped)QuantityShipped,
    Case when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 7 ) then 7
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 14 ) then 14
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 30 ) then 30
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 90 ) then 90
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 180 ) then 180 
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 365 ) then 365 END as SalesDays
    from OrderDetail
    inner join MPDetail
    on(OrderDetail.MPDetailID=MPDetail.MPDetailID)
    inner join  OrderItemDetail
    on(OrderDetail.OrderDetailID=OrderItemDetail.OrderDetailID)

    Group by SellerSKU,MPDetail.MarketPlaceCode,Case when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 7 ) then 7
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 14 ) then 14
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 30 ) then 30
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 90 ) then 90
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 180 ) then 180 
            when (DATEDIFF(dd,OrderDetail.PurchaseDate,getDate()) <= 365 ) then 365 END 
    )
    as SalesData
    pivot
    (
        Min(QuantityShipped) For SalesDays in('+@PivotColumns+')
    )AS USAPivotData'

    Print @SQLQuery

    exec (@SQLQuery)

答案 2 :(得分:0)

    CREATE TABLE #t  ( Dates DATE, Orders INT,CancelledOrders INT)
    INSERT INTO #t
    SELECT '2016-01-17',100 ,50  UNION         
    SELECT '2016-01-18',120 ,20  UNION         
    SELECT '2016-01-20',150 ,30  



    DECLARE @cols VARCHAR(max),@sql VARCHAR(MAX)
    SELECT @cols=ISNULL(@cols+',[','[')+CONVERT(VARCHAR,dates)+']' FROM #t GROUP BY Dates
    PRINT @cols

    SET @sql=' SELECT *  FROM (
       SELECT c.t,c.v,dates FROM #t
       CROSS APPLY(VALUES(''Orders'',Orders),(''CancelledOrders'',CancelledOrders))AS c(t,v)
   ) AS t
   PIVOT(MAX(v) FOR dates IN ('+@cols+')) p'

   EXEC(@sql)
t               2016-01-17  2016-01-18  2016-01-20
--------------- ----------- ----------- -----------
CancelledOrders 50          20          30
Orders          100         120         150

答案 3 :(得分:0)

不使用SQL Server的数据透视选项,旧版本可以是这样的:

declare @sql nvarchar(max) = '', @sqla nvarchar(max) = '', @sqlb nvarchar(max) = '', @sqlc nvarchar(max) = '';
select  
    @sqla = @sqla + N',case when Dates = ''' + Dates + N''' then Orders end [' + Dates + N']',
    @sqlb = @sqlb + N',case when Dates = ''' + Dates + N''' then [Cancelled Orders] end [' + Dates + N']',
    @sqlc = @sqlc + N',max([' + Dates + ']) [' + Dates + ']'
from yourTable;
select @sql = N'select Dates' + @sqlc  + N' from (select ''Orders'' Dates' + @sqla + 
              N' from yourTable union all select ''Cancelled Orders'' Dates' + @sqlb + 
              N' from yourTable) t group by Dates';
exec(@sql);