【问题标题】:SQLServer - Multiple PIVOT on same columnsSQL Server - 同一列上的多个 PIVOT
【发布时间】:2014-12-30 14:43:35
【问题描述】:

我很想知道我是否可以像这样在 sql server 的同一列上执行多个 PIVOT:

WITH T(ID, NAME, MSNAME, PLANED, ACTUAL)
AS (
    SELECT 1, '45rpm', 'Raised to Supplier', '2014-12-17', '2015-12-17' UNION ALL
    SELECT 1, '45rpm', 'Base Test Date', '2014-12-18', '2015-12-18' UNION ALL
    SELECT 1, '45rpm', 'Washing Approval', '2014-12-19', '2015-12-19'
)
SELECT ID, NAME
  , MAX(CASE WHEN MSNAME LIKE 'Raised to Supplier' THEN PLANED END) AS 'Raised to Supplier (PLANED)'
  , MAX(CASE WHEN MSNAME LIKE 'Base Test Date' THEN PLANED END) AS 'Base Test Date (PLANED)'
  , MAX(CASE WHEN MSNAME LIKE 'Washing Approval' THEN PLANED END) AS 'Washing Approval (PLANED)'
  , MAX(CASE WHEN MSNAME LIKE 'Raised to Supplier' THEN ACTUAL END) AS 'Raised to Supplier (ACTUAL)'
  , MAX(CASE WHEN MSNAME LIKE 'Base Test Date' THEN ACTUAL END) AS 'Base Test Date (ACTUAL)'
  , MAX(CASE WHEN MSNAME LIKE 'Washing Approval' THEN ACTUAL END) AS 'Washing Approval (ACTUAL)'
FROM T
GROUP BY ID, NAME

对于PLANED 列,它运行良好,但我无法添加第二列ACTUAL(如上例所示↑)

WITH T(ID, NAME, MSNAME, PLANED, ACTUAL)
AS (
    SELECT 1, '45rpm', 'Raised to Supplier', '2014-12-17', '2015-12-17' UNION ALL
    SELECT 1, '45rpm', 'Base Test Date', '2014-12-18', '2015-12-18' UNION ALL
    SELECT 1, '45rpm', 'Washing Approval', '2014-12-19', '2015-12-19'
)
SELECT ID, NAME
  , MAX([Raised to Supplier]) AS 'Raised to Supplier (PLANED)'
  , MAX([Base Test Date]) AS 'Base Test Date (PLANED)'
  , MAX([Washing Approval]) AS 'Washing Approval (PLANED)' FROM T
PIVOT
(
    max(PLANED)
    FOR MSNAME IN ([Raised to Supplier],[Base Test Date],[Washing Approval])
) AS p1
GROUP BY ID, NAME

编辑:

PIVOT 关键字的限制很少,其中一个已在此处讨论过,即 SQL 服务器不支持 PIVOT 中的多重聚合 - Giorgos 评论说 [类似于 PIVOT (min(), max(), sum() ...)]

有 3 种替代方法可以应对这种情况:

  1. 不带 PIVOT 关键字的 case 语句的一般解决方案(如上面的第一个示例所示)
  2. 首先取消透视数据,然后对它们进行透视(在聚合之前增加行并合并列)[@bluefeet 回答]
  3. 复制列以进行第二次聚合[@NoDisplayName 回答]

了解后我认为这个问题的标题应该是:单个 PIVOT() 中的多个聚合而不是现有的一个

【问题讨论】:

  • 好吧,你试试怎么样?
  • TSQL 支持 PIVOT 中的多个聚合。
  • 很难选择任何一个答案。 @NoDisplayName@bluefeet 都展示了他们的创造力,我测试的两个答案都正常工作。是时候让我“Eeny, meeny, miny, moe”了

标签: sql sql-server pivot


【解决方案1】:

要旋转multiple column,您需要使用Muliple Pivot's 而不是multiple Aggregates。试试这个。

SELECT ID,
       NAME,
       Max([Raised to Supplier(PLANED)])[Raised to Supplier(PLANED)],
       Max([Base Test Date(PLANED)])[Base Test Date(PLANED)],
       Max([Washing Approval(PLANED)])[Washing Approval(PLANED)],
       Max([Raised to Supplier(ACTUAL)])[Raised to Supplier(ACTUAL)],
       Max([Base Test Date(ACTUAL)])[Base Test Date(ACTUAL)],
       Max([Washing Approval(ACTUAL)])[Washing Approval(ACTUAL)]
FROM   (SELECT 1 ID,'45rpm' NAME,'Raised to Supplier' + '(PLANED)' MSNAME_pl,'Raised to Supplier' + '(ACTUAL)' MSNAME_ac,'2014-12-17' PLANED,'2015-12-17' ACTUAL
        UNION ALL
        SELECT 1,'45rpm','Base Test Date' + '(PLANED)','Base Test Date' + '(ACTUAL)','2014-12-18','2015-12-18'
        UNION ALL
        SELECT 1,'45rpm','Washing Approval' + '(PLANED)','Washing Approval' + '(ACTUAL)','2014-12-19','2015-12-19') a
       PIVOT ( Max(PLANED)
             FOR MSNAME_pl IN ([Raised to Supplier(PLANED)],
                               [Base Test Date(PLANED)],
                               [Washing Approval(PLANED)]) ) AS p1 

        PIVOT ( MAX(ACTUAL) 
              FOR MSNAME_ac IN ([Raised to Supplier(ACTUAL)],
                                [Base Test Date(ACTUAL)],
                                [Washing Approval(ACTUAL)])) p2
GROUP BY ID, NAME

【讨论】:

    【解决方案2】:

    SQL Server 不允许在多个列上进行透视,我实际上建议先查看取消透视PlanedActual 列,然后将数据透视为您想要的最终结果。

    您没有指定您使用的 SQL Server 版本,但您可以使用 UNPIVOT 函数或使用 CROSS APPLY 将多列转换为多行。基本语法是:

    select 
      id,
      name, 
      new_col = msname + '_' + col,
      value
    from t
    cross apply
    (
      select 'planed', planed union all
      select 'actual', actual
    ) c (col, value);
    

    SQL Fiddle with Demo。这会将您的数据转换为以下格式:

    | ID |  NAME |                   NEW_COL |      VALUE |
    |----|-------|---------------------------|------------|
    |  1 | 45rpm | Raised to Supplier_planed | 2014-12-17 |
    |  1 | 45rpm | Raised to Supplier_actual | 2015-12-17 |
    |  1 | 45rpm |     Base Test Date_planed | 2014-12-18 |
    |  1 | 45rpm |     Base Test Date_actual | 2015-12-18 |
    |  1 | 45rpm |   Washing Approval_planed | 2014-12-19 |
    |  1 | 45rpm |   Washing Approval_actual | 2015-12-19 |
    

    您现在拥有所需的新列名以及单列中的值,而不是多列。现在您可以将数据转换为最终结果:

    select id, name, 
      [Raised to Supplier_planed], [Raised to Supplier_actual],
      [Base Test Date_planed], [Base Test Date_actual],
      [Washing Approval_planed], [Washing Approval_actual]
    from
    (
      select 
        id,
        name, 
        new_col = msname + '_' + col,
        value
      from t
      cross apply
      (
        select 'planed', planed union all
        select 'actual', actual
      ) c (col, value)
    ) d
    pivot
    (
      max(value)
      for new_col in ([Raised to Supplier_planed], [Raised to Supplier_actual],
                      [Base Test Date_planed], [Base Test Date_actual],
                      [Washing Approval_planed], [Washing Approval_actual])
    ) p;
    

    SQL Fiddle with Demo。这给出了相同的最终结果:

    | ID |  NAME | RAISED TO SUPPLIER_PLANED | RAISED TO SUPPLIER_ACTUAL | BASE TEST DATE_PLANED | BASE TEST DATE_ACTUAL | WASHING APPROVAL_PLANED | WASHING APPROVAL_ACTUAL |
    |----|-------|---------------------------|---------------------------|-----------------------|-----------------------|-------------------------|-------------------------|
    |  1 | 45rpm |                2014-12-17 |                2015-12-17 |            2014-12-18 |            2015-12-18 |              2014-12-19 |              2015-12-19 |
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-02
      • 1970-01-01
      • 2012-10-15
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多