如何在sql中创建计算的数据透视表

时间:2015-11-05 10:19:55

标签: sql sql-server pivot pivot-table

方案

XYZ公司销售产品。公司通过检查完成整个订单所需的时间来衡量其绩效。每个订单都经历多个状态(例如:打开,待定,关闭)

他们会计算每个状态的天数,以了解订单在特定状态下的天数。日期以两种不同的方式计算,即工作日和日历天

请参阅下表:

enter image description here

问题

如何将此表转换为下图所示的数据透视表?还有如何添加到每个工作日和工作日状态总计的其他列。

期望的结果:

enter image description here

1 个答案:

答案 0 :(得分:1)

你可以这样做:

SELECT *
FROM
(
    SELECT 
        OrderID,
        OrderStatus + CountType AS StatusType,
        DayCount
    FROM CalendarTable     
    UNION ALL
    SELECT 
    OrderID,
    CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
    DayCount
    FROM CalendarTable
) AS t
PIVOT
(
   MAX(DayCount)
   For StatusType IN(OpenWorking,
                     OpenCalendar,
                     CloseWorking,
                     CloseCalendar,
                     PendingWorking,
                     PendingCalendar,
                     TotalWorking,
                     TotalCalendar)
) AS p;

这会给你:

enter image description here

如果您不想手动记下所有状态,那么您可以动态地执行:

DECLARE @cols AS NVARCHAR(MAX);

DECLARE @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT distinct ',' +
                        QUOTENAME(StatusType)
                       FROM 
                       (
                            SELECT 
                              OrderID,
                              OrderStatus + CountType AS StatusType,
                              DayCount
                            FROM CalendarTable     
                            UNION ALL
                            SELECT 
                              OrderID,
                              CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
                              DayCount
                            FROM CalendarTable
                        ) AS t
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');


SELECT @query = 'SELECT *
                FROM
                (
                    SELECT 
                      OrderID,
                      OrderStatus + CountType AS StatusType,
                      DayCount
                    FROM CalendarTable     
                    UNION ALL
                    SELECT 
                      OrderID,
                      CASE WHEN CountType = ''Working'' THEN ''TotalWorking'' ELSE ''TotalCalendar'' END,
                      DayCount
                    FROM CalendarTable
                ) AS t
                PIVOT
                (
                   MAX(DayCount)
                   For StatusType IN(' + @cols + ')' +
                  ') p';

execute(@query);

<强>更新

对于列名,您可以创建一个新变量@colnames并使用您想要的名称填充它。对于Totals,您可以添加WHERE子句以使状态的总数仅为活动和待处理状态。所以你的查询将是这样的:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @colnames AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT distinct ',' +
                        QUOTENAME(StatusType)
                       FROM 
                       (
                            SELECT 
                              OrderID,
                              OrderStatus + CountType AS StatusType,
                              DayCount
                            FROM CalendarTable     
                            UNION ALL
                            SELECT 
                              OrderID,
                              CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
                              DayCount
                            FROM CalendarTable
                            WHERE OrderStatus IN('Active', 'Pending')
                        ) AS t
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');


SELECT @colnames = STUFF((SELECT distinct ',' +
                        QUOTENAME(StatusType) + ' AS ' + QUOTENAME(StatusTypeName)
                       FROM 
                       (
                           SELECT 
                                OrderID,
                                OrderStatus + CountType AS StatusType,
                                DayCount,
                                OrderStatus + CASE WHEN CountType = 'Working' THEN  'WorkDays' ELSE 'CalDays' END AS StatusTypeName
                            FROM CalendarTable     
                            UNION ALL
                            SELECT 
                              OrderID,
                              CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
                              DayCount,
                              CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END
                            FROM CalendarTable
                            WHERE OrderStatus IN('Active', 'Pending')
                        ) AS t
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SELECT @query = 'SELECT OrderID , ' + @colnames + '
                FROM
                (
                    SELECT 
                      OrderID,
                      OrderStatus + CountType AS StatusType,
                      DayCount
                    FROM CalendarTable     
                    UNION ALL
                    SELECT 
                      OrderID,
                      CASE WHEN CountType = ''Working'' THEN ''TotalWorking'' ELSE ''TotalCalendar'' END,
                      DayCount
                    FROM CalendarTable
                    WHERE OrderStatus IN(''Active'', ''Pending'')
                ) AS t
                PIVOT
                (
                   SUM(DayCount)
                   For StatusType IN(' + @cols + ')' +
                  ') p';

execute(@query);

这会给你:

enter image description here

更新

如果要在手动数据透视查询中添加where子句,可以执行以下操作:

SELECT *
FROM
(
    SELECT 
        OrderID,
        OrderStatus + CountType AS StatusType,
        DayCount
    FROM CalendarTable     
    WHERE ...
    UNION ALL
    SELECT 
    OrderID,
    CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
    DayCount
    FROM CalendarTable
    WHERE ...
) AS t
PIVOT
(
   MAX(DayCount)
   For StatusType IN(OpenWorking,
                     OpenCalendar,
                     CloseWorking,
                     CloseCalendar,
                     PendingWorking,
                     PendingCalendar,
                     TotalWorking,
                     TotalCalendar)
) AS p;