为什么使用"额外"列进行旋转不会合并结果

Dav*_*ugg 8 sql t-sql sql-server pivot

我知道很多人都观察过这种行为,但我想知道是否有人可以解释原因.当我创建一个小表来创建使用pivot函数的示例时,我得到了我期望的结果:

CREATE TABLE dbo.AverageFishLength
    (
      Fishtype VARCHAR(50) ,
      AvgLength DECIMAL(8, 2) ,
      FishAge_Years INT
    )
INSERT  INTO dbo.AverageFishLength
        ( Fishtype, AvgLength, FishAge_Years )
VALUES  ( 'Muskie', 32.75, 3 ),
        ( 'Muskie', 37.5, 4 ),
        ( 'Muskie', 39.75, 5 ),
        ( 'Walleye', 16.5, 3 ),
        ( 'Walleye', 18.25, 4 ),
        ( 'Walleye', 20.0, 5 ),
        ( 'Northern Pike', 20.75, 3 ),
        ( 'Northern Pike', 23.25, 4 ),
        ( 'Northern Pike', 26.0, 5 );
Run Code Online (Sandbox Code Playgroud)

这是透视查询:

SELECT  Fishtype ,
        [3] AS [3 Years Old] ,
        [4] AS [4 Years Old] ,
        [5] AS [5 Years Old]
FROM    dbo.AverageFishLength   PIVOT( SUM(AvgLength) 
                                FOR FishAge_Years IN ( [3], [4], [5] ) ) AS PivotTbl
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述

但是,如果我使用标识列创建表,则结果将分成不同的行:

DROP TABLE dbo.AverageFishLength
CREATE TABLE dbo.AverageFishLength
    (
      ID INT IDENTITY(1,1) ,
      Fishtype VARCHAR(50) ,
      AvgLength DECIMAL(8, 2) ,
      FishAge_Years INT
    )
INSERT  INTO dbo.AverageFishLength
        ( Fishtype, AvgLength, FishAge_Years )
VALUES  ( 'Muskie', 32.75, 3 ),
        ( 'Muskie', 37.5, 4 ),
        ( 'Muskie', 39.75, 5 ),
        ( 'Walleye', 16.5, 3 ),
        ( 'Walleye', 18.25, 4 ),
        ( 'Walleye', 20.0, 5 ),
        ( 'Northern Pike', 20.75, 3 ),
        ( 'Northern Pike', 23.25, 4 ),
        ( 'Northern Pike', 26.0, 5 );
Run Code Online (Sandbox Code Playgroud)

同样的查询:

SELECT  Fishtype ,
        [3] AS [3 Years Old] ,
        [4] AS [4 Years Old] ,
        [5] AS [5 Years Old]
FROM    dbo.AverageFishLength   PIVOT( SUM(AvgLength) 
                                FOR FishAge_Years IN ( [3], [4], [5] ) ) AS PivotTbl
Run Code Online (Sandbox Code Playgroud)

结果不同:

在此输入图像描述

在我看来,ID列正在查询中使用,即使它根本没有出现在查询中.它几乎就像隐含在查询中,但未在结果集中显示.

谁能解释为什么会这样?

Tar*_*ryn 13

之所以会发生这种情况是因为该ID列对于每一行都是唯一的,并且由于您直接查询表(没有子查询),该列作为GROUP BY聚合函数需求的一部分包含在内.

该文档的约MSDN文档FROM状态如下:

table_source PIVOT <pivot_clause>

指定table_source基于pivot_column进行透视.table_source是表或表的表达式.输出是一个表,其中包含table_source的所有列,pivot_column和value_column除外.除了pivot_column和value_column之外,table_source称为pivot运算符的分组列.

PIVOT对输入表执行关于分组列的分组操作,并为每个组返回一行.此外,输出包含在column_list中指定的每个值的一列,该列出现在input_table的pivot_column中.

你的版本基本上是在说SELECT * FROM yourtablePIVOT那个数据.即使ID列不在最终的SELECT列表中,它也是查询中的分组元素.如果您将PIVOT与"pre-PIVOT"示例进行比较,以显示您将看到您的版本.此示例使用CASE表达式和聚合函数:

SELECT Fishtype,
  sum(case when FishAge_Years = 3 then AvgLength else 0 end) as [3],
  sum(case when FishAge_Years = 4 then AvgLength else 0 end) as [4],
  sum(case when FishAge_Years = 5 then AvgLength else 0 end) as [5]
FROM dbo.AverageFishLength
GROUP BY Fishtype, ID;
Run Code Online (Sandbox Code Playgroud)

结果将会有所偏差,因为即使您没有ID最终列表,它仍然被用于分组,因为它们是唯一的,您将得到多行.

使用PIVOT时解决此问题的最简单方法是使用子查询:

SELECT Fishtype ,
        [3] AS [3 Years Old] ,
        [4] AS [4 Years Old] ,
        [5] AS [5 Years Old]
FROM
(
  SELECT Fishtype, 
    AvgLength, 
    FishAge_Years
  FROM    dbo.AverageFishLength
) d
PIVOT
( 
  SUM(AvgLength) 
  FOR FishAge_Years IN ( [3], [4], [5] ) 
) AS PivotTbl;
Run Code Online (Sandbox Code Playgroud)

在此版本中,您只返回表中实际需要和想要的列 - 这不包括在内,ID因此不会用于对数据进行分组.