【问题标题】:GROUP BY statement with a PIVOT command in T-SQLT-SQL 中带有 PIVOT 命令的 GROUP BY 语句
【发布时间】:2019-06-06 12:02:44
【问题描述】:

我有一个涉及创建正确表的 PIVOT 命令的 SQL 查询,但现在我需要对其中一列进行 GROUP。

当我尝试添加 GROUP BY 语句时,它返回以下错误:“列 'PivotTable.1' 在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中。”

SELECT [Load ID],[1],[2],[3],[4]
FROM TMS_Load_Stops
PIVOT (
    MIN([Stop Zip])
    for [Sequence] IN ([1],[2],[3],[4])
    ) PivotTable
;

原始代码产生以下结果:

我希望结果如下(出于解释目的,值是随机数):

【问题讨论】:

  • 你想在这里做什么?,编辑问题添加一些示例数据和期望的结果会有所帮助。
  • 您不能仅按 1 列分组。也许是不同的?也许是完全不同的东西?我的猜测是这里的方法不太正确。但如果没有样本数据和所需的输出,这只是猜测。

标签: sql sql-server tsql group-by pivot


【解决方案1】:

如果您省略 Group by 子句,它会自动将 [Load ID] 作为分组列。我们在数据透视表中有三种类型的列——分组列、聚合列和跨越列。这里分组是[Load ID],跨越是[Sequence],聚合是[Stop Zip]。 使用以下查询。

SELECT [Load ID],[1],[2],[3],[4]
FROM TMS_Load_Stops
PIVOT (
    MIN([Stop Zip])
    for [Sequence] IN ([1],[2],[3],[4])
    ) PivotTable

【讨论】:

    【解决方案2】:

    您必须在PIVOT 之前“投影”TMS_Load_Stops 中的任何其他列,因为它已经执行分组 - 使用 PIVOT 中未提及的所有列:

    SELECT [Load ID],[1],[2],[3],[4]
    FROM (select [Load ID],[Sequence],[Stop Zip] from TMS_Load_Stops) t
    PIVOT (
        MIN([Stop Zip])
        for [Sequence] IN ([1],[2],[3],[4])
        ) PivotTable
    ;
    

    【讨论】:

      【解决方案3】:

      这里是为每个字段指定聚合方法和实现的示例:

      SELECT 
          [Load ID]
          ,sum([1]) AS [1]
          ,sum([2]) AS [2]
          ,sum([3]) AS [3]
          ,sum([4]) AS [4]
      FROM (select * from TMS_Load_Stops) src
      PIVOT (
          MIN([Stop Zip])
          for [Sequence] IN ([1],[2],[3],[4])
          ) PivotTable
      GROUP BY [Load ID]
      ;
      

      在第 3-6 行中,我们添加了一个聚合方法“SUM”,以便在聚合时对字段记录求和。这样,解释器就知道在使用 'GROUP BY' 进行分组时如何进行聚合。

      ^ 我们希望尽可能避免使用条件“CASE WHEN”,因为它的计算成本很高。 PIVOT 按预期工作;它将字段值关系分解为它们自己的列。

      您还可以通过再次调用数据透视表作为“通用表表达式”来引用它。这样,'GROUP BY' 语法是隐式的。它看起来像这样:

      Select * from (
          SELECT 
              [Load ID]
              ,[1]
              ,[2]
              ,[3]
              ,[4]
          FROM (select * from TMS_Load_Stops) src
          PIVOT (
              MIN([Stop Zip])
              for [Sequence] IN ([1],[2],[3],[4])
              ) PivotTable 
      ) AggregatedPivot
          ;
      

      【讨论】:

        【解决方案4】:

        使用条件聚合。它更简单:

        SELECT [Load ID],
               MIN(CASE WHEN [Sequence] = 1 THEN [Stop Zip] END) as [1],
               MIN(CASE WHEN [Sequence] = 2 THEN [Stop Zip] END) as [2],
               MIN(CASE WHEN [Sequence] = 3 THEN [Stop Zip] END) as [3],
               MIN(CASE WHEN [Sequence] = 4 THEN [Stop Zip] END) as [4],
        FROM TMS_Load_Stops
        GROUP BY [Load ID];
        

        PIVOT 不起作用,因为您在表中有其他列正在被透视。我只是不喜欢语法或它的工作方式,但您也可以通过仅选择您需要的列来修复它:

        SELECT [Load ID], [1], [2], [3], [4]
        FROM (SELECT [Load ID], [Sequence], [Stop Zip]
              FROM TMS_Load_Stops
             ) ls
        PIVOT (
            MIN([Stop Zip])
            for [Sequence] IN ([1],[2],[3],[4])
            ) PivotTable
        ;
        

        【讨论】:

        • 谢谢!结果正是我想要的
        • 在这里使用条件是计算密集型的并且会消耗资源。它适用于对小型数据帧的快速 1-off 分析;但最佳方法是 PIVOT。您使用“分组依据”来定义要聚合的键。否则,PIVOT 只是将标签-值对分解成列,其中每个唯一记录都有自己的行……这很好;这是一个支点。用你的键添加一个“GROUP BY”子句,你比使用“CASE WHEN”要好得多。您还需要在字段上指定聚合方法并为其指定别名以使 GROUP BY 起作用。
        猜你喜欢
        • 1970-01-01
        • 2013-01-27
        • 2011-01-28
        • 1970-01-01
        • 1970-01-01
        • 2013-03-25
        • 1970-01-01
        • 1970-01-01
        • 2017-01-03
        相关资源
        最近更新 更多