【问题标题】:How to pivot on multiple columns?如何在多个列上进行旋转?
【发布时间】:2017-11-16 07:34:44
【问题描述】:

我正在尝试以多个列为中心,并且我正在使用 SQL Server 2014,但是,我无法弄清楚如何做到这一点。到目前为止,这是我尝试过的:

DECLARE @Table TABLE (
    Name NVARCHAR(MAX),
    TypeId INT,
    TotalOrders INT,
    GrandTotal MONEY
)

INSERT INTO @Table
    (Name, TypeId, TotalOrders, GrandTotal)
VALUES
    ('This Month', 1, 10, 1),
    ('This Month', 2, 5, 7),
    ('This Week', 1, 8, 3),
    ('Last Week', 1, 8, 12),
    ('Yesterday', 1, 10, 1),
    ('Yesterday', 2, 1, 5)

这会产生以下结果:

Name                             TypeId      TotalOrders GrandTotal
-------------------------------- ----------- ----------- ---------------------
This Month                       1           10          1.00
This Month                       2           5           7.00
This Week                        1           8           3.00
Last Week                        1           8           12.00
Yesterday                        1           10          1.00
Yesterday                        2           1           5.00

要将这些行放入列中,我已经尝试过:

SELECT
    TypeId,
    ISNULL([Yesterday], 0) AS YesterdayTotalOrders,
    ISNULL([This Week], 0) AS ThisWeekTotalOrders,
    ISNULL([Last Week], 0) AS LastWeekTotalOrders,
    ISNULL([This Month], 0) AS ThisMonthTotalOrders
FROM
    (SELECT Name, TypeId, TotalOrders FROM @Table) AS src
PIVOT (
    SUM(TotalOrders) FOR Name IN (
        [Yesterday],
        [This Week],
        [Last Week],
        [This Month]
    )
) AS p1

这会产生以下结果集:

TypeId      YesterdayTotalOrders ThisWeekTotalOrders LastWeekTotalOrders ThisMonthTotalOrders
----------- -------------------- ------------------- ------------------- --------------------
1           10                   8                   8                   10
2           1                    0                   0                   5

现在,我需要为GrandTotal 提供一些其他列,例如YesterdayGrandTotalThisWeekGrandTotal 等等,但我不知道如何实现这一点。

任何帮助将不胜感激。

更新#1:这是预期的结果集:

TypeId      YesterdayTotalOrders ThisWeekTotalOrders LastWeekTotalOrders ThisMonthTotalOrders YesterdayGrandTotal   ThisWeekGrandTotal    LastWeekGrandTotal    ThisMonthGrandTotal
----------- -------------------- ------------------- ------------------- -------------------- --------------------- --------------------- --------------------- ---------------------
1           10                   8                   8                   10                   1.00                  3.00                  12.00                 1.00
2           1                    0                   0                   5                    5.00                  0.00                  0.00                  7.00

【问题讨论】:

    标签: sql sql-server pivot sql-server-2014


    【解决方案1】:

    条件聚合可能是一个解决方案:

    select typeID,
        SUM(case when name = 'Yesterday' then totalOrders else 0 end) as YesterdayTotalOrders,
        SUM(case when name = 'This Week' then totalOrders else 0 end) as ThisWeekTotalOrders,
        SUM(case when name = 'Last Week' then totalOrders else 0 end) as LastWeekTotalOrders,
        SUM(case when name = 'This Month' then totalOrders else 0 end) as ThisMonthTotalOrders,
        SUM(case when name = 'Yesterday' then GrandTotal else 0 end) as YesterdayGrandTotal,
        SUM(case when name = 'This Week' then GrandTotal else 0 end) as ThisWeekGrandTotal,
        SUM(case when name = 'Last Week' then GrandTotal else 0 end) as LastWeekGrandTotal,
        SUM(case when name = 'This Month' then GrandTotal else 0 end) as ThisMonthGrandTotal    
    from @table
    group by typeID
    

    或者,您可以像这样使用CROSS APPLYPIVOT

    SELECT
        TypeId,
        ISNULL([Yesterday], 0) AS YesterdayTotalOrders,
        ISNULL([This Week], 0) AS ThisWeekTotalOrders,
        ISNULL([Last Week], 0) AS LastWeekTotalOrders,
        ISNULL([This Month], 0) AS ThisMonthTotalOrders,
        ISNULL([grant Yesterday], 0) AS YesterdayGrandTotal,
        ISNULL([grant This Week], 0) AS ThisWeekGrandTotal,
        ISNULL([grant Last Week], 0) AS LastWeekGrandTotal,
        ISNULL([grant This Month], 0) AS ThisMonthGrandTotal
    FROM
        (
          SELECT t.* 
          FROM @Table
          CROSS APPLY (values(Name, TypeId, TotalOrders),
                         ('grant ' + Name, TypeId, GrandTotal)) 
                         t(Name, TypeId, TotalOrders)
        ) AS src
    PIVOT (
        SUM(TotalOrders) FOR Name IN (
            [Yesterday],
            [This Week],
            [Last Week],
            [This Month],
            [grant Yesterday],
            [grant This Week],
            [grant Last Week],
            [grant This Month]
        )
    ) AS p1
    

    demo

    两种解决方案都只会扫描输入表一次,并且它们的查询计划非常相似。这两种解决方案都优于两个枢轴的JOIN(我最初提供的解决方案),因为两个枢轴需要扫描输入表两次。

    【讨论】:

    • 谢谢。我喜欢条件聚合解决方案,但让我看看其他人是否可以提出任何更好的解决方案,然后再将此作为答案。再次感谢您。
    【解决方案2】:

    您还可以使用CTE,将pivots..P1TotalOrders 分开,P2GrandTotal 分开

    ;WITH CTE AS 
       (
         SELECT
        P1.TypeId,
        ISNULL(P1.[Yesterday], 0) AS YesterdayTotalOrders,
        ISNULL(P1.[This Week], 0) AS ThisWeekTotalOrders,
        ISNULL(P1.[Last Week], 0) AS LastWeekTotalOrders,
        ISNULL(P1.[This Month], 0) AS ThisMonthTotalOrders
    FROM
        (SELECT Name, TypeId, TotalOrders FROM @Table) AS src
    PIVOT (SUM(TotalOrders) FOR src.Name IN (
            [Yesterday],
            [This Week],
            [Last Week],
            [This Month])) AS P1
       ), CTE1 AS 
       (
    
    SELECT
        P1.TypeId,
        ISNULL(P1.[Yesterday], 0) AS YesterdayGrandTotal,
        ISNULL(P1.[This Week], 0) AS ThisWeekTGrandTotal,
        ISNULL(P1.[Last Week], 0) AS LastWeekGrandTotal,
        ISNULL(P1.[This Month], 0) AS ThisMonthGrandTotal
    FROM
        (SELECT Name, TypeId, GrandTotal FROM @Table) AS src
    PIVOT (SUM(GrandTotal) FOR src.Name IN (
            [Yesterday],
            [This Week],
            [Last Week],
            [This Month])) AS P1 
           )
    
           SELECT C.TypeId  ,    C.YesterdayTotalOrders, C.ThisWeekTotalOrders, C.LastWeekTotalOrders, C.ThisMonthTotalOrders , C1.YesterdayGrandTotal  , C1.ThisWeekTGrandTotal ,C1.LastWeekGrandTotal , C1.ThisMonthGrandTotal FROM CTE C 
           INNER JOIN CTE1 C1 ON C1.TypeId = C.TypeId
    

    结果:

    TypeId      YesterdayTotalOrders ThisWeekTotalOrders LastWeekTotalOrders ThisMonthTotalOrders YesterdayGrandTotal   ThisWeekGrandTotal    LastWeekGrandTotal    ThisMonthGrandTotal
    ----------- -------------------- ------------------- ------------------- -------------------- --------------------- --------------------- --------------------- ---------------------
    1           10                   8                   8                   10                   1.00                  3.00                  12.00                 1.00
    2           1                    0                   0                   5                    5.00                  0.00                  0.00                  7.00
    

    【讨论】:

    • 上述问题没有更好的解决方案吗?我的意思是有没有可能在不使用连接的情况下实现同样的事情?因为据我了解,这意味着必须获取两次 @Table 记录,每次 CTE 一次(并且在我的实际场景中计算这一点并不便宜)。我希望仅使用 PIVOT 以某种方式获得相同的结果集。有什么建议吗?
    • @Mehdi 允许多个pivot 选项,但在您的情况下,您的同一列对于多个pivot 无效。
    • 拥有“同一列”是什么意思?你能详细说明一下吗?
    • @Mehdi 相同的列(找到相同的 name 列值)
    【解决方案3】:

    在 oracle 中,我会做类似 tihs 的事情。对我来说很好用

    select * from (
    SELECT   Name, TypeId,TotalOrders
    --hier
    ,GrandTotal 
    FROM test_b )
    PIVOT (  SUM(TotalOrders)TotalOrders, 
    --hier
    SUM(grandtotal) grandtotal FOR Name IN 
    ('Yesterday'Yesterday,'This Week'ThisWeek,'Last Week'LastWeek,'This 
    Month'ThisMonth )
    ) ;
    

    所以在 sql server 中试试这个

    SELECT *
       /* TypeId,
        ISNULL([Yesterday], 0) AS YesterdayTotalOrders,
        ISNULL([This Week], 0) AS ThisWeekTotalOrders,
       ISNULL([Last Week], 0) AS LastWeekTotalOrders,
       ISNULL([This Month], 0) AS ThisMonthTotalOrders*/
    FROM
       (SELECT Name, TypeId, TotalOrders
       ,grandtotal 
      FROM @Table) AS src
    PIVOT (
        SUM(TotalOrders)TotalOrders, SUM(grandtotal)grandtotal FOR Name IN (
        [Yesterday]Yesterday,
        [This Week]ThisWeek,
        [Last Week]LastWeek,
        [This Month]ThisMonth
       )
     ) AS p1
    

    【讨论】:

      猜你喜欢
      • 2013-11-26
      • 2021-04-21
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多