sql - 在 SQL 中转置列和行的简单方法?

标签 sql sql-server tsql pivot

如何在 SQL 中简单地切换列与行? 有没有简单的转置命令?

即转这个结果:

        Paul  | John  | Tim  |  Eric
Red     1       5       1       3
Green   8       4       3       5
Blue    2       2       9       1

进入此:

        Red  | Green | Blue
Paul    1       8       2
John    5       4       2
Tim     1       3       9
Eric    3       5       1

PIVOT 对于这种情况来说似乎太复杂了。

最佳答案

有多种方法可以转换此数据。在您原来的帖子中,您指出 PIVOT 对于这种情况来说似乎太复杂,但使用 UNPIVOT and PIVOT 可以非常轻松地应用它。 SQL Server 中的函数。

但是,如果您无权访问这些函数,可以使用 UNION ALL 复制到 UNPIVOT,然后使用带有 CASE 的聚合函数code> 语句到 PIVOT:

创建表:

CREATE TABLE yourTable([color] varchar(5), [Paul] int, [John] int, [Tim] int, [Eric] int);

INSERT INTO yourTable
    ([color], [Paul], [John], [Tim], [Eric])
VALUES
    ('Red', 1, 5, 1, 3),
    ('Green', 8, 4, 3, 5),
    ('Blue', 2, 2, 9, 1);

Union All、聚合和 CASE 版本:

select name,
  sum(case when color = 'Red' then value else 0 end) Red,
  sum(case when color = 'Green' then value else 0 end) Green,
  sum(case when color = 'Blue' then value else 0 end) Blue
from
(
  select color, Paul value, 'Paul' name
  from yourTable
  union all
  select color, John value, 'John' name
  from yourTable
  union all
  select color, Tim value, 'Tim' name
  from yourTable
  union all
  select color, Eric value, 'Eric' name
  from yourTable
) src
group by name

参见SQL Fiddle with Demo

UNION ALL 通过将 Paul、John、Tim、Eric 列转换为单独的行来执行数据的 UNPIVOT。然后,您将聚合函数 sum()case 语句一起应用,以获取每种颜色的新列。

逆透视和透视静态版本:

SQL Server 中的 UNPIVOTPIVOT 函数使这种转换变得更加容易。如果您知道要转换的所有值,则可以将它们硬编码为静态版本以获得结果:

select name, [Red], [Green], [Blue]
from
(
  select color, name, value
  from yourtable
  unpivot
  (
    value for name in (Paul, John, Tim, Eric)
  ) unpiv
) src
pivot
(
  sum(value)
  for color in ([Red], [Green], [Blue])
) piv

参见SQL Fiddle with Demo

使用UNPIVOT 的内部查询执行与UNION ALL 相同的功能。它获取列列表并将其转换为行,然后PIVOT执行最终转换为列。

动态枢轴版本:

如果您的列数未知(示例中为 Paul、John、Tim、Eric),并且要转换的颜色数未知,您可以使用动态 sql 生成列表来UNPIVOT,然后PIVOT:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name <> 'color'
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(color)
                    from yourtable t
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query 
  = 'select name, '+@colsPivot+'
      from
      (
        select color, name, value
        from yourtable
        unpivot
        (
          value for name in ('+@colsUnpivot+')
        ) unpiv
      ) src
      pivot
      (
        sum(value)
        for color in ('+@colsPivot+')
      ) piv'

exec(@query)

参见SQL Fiddle with Demo

动态版本先查询 yourtable,然后查询 sys.columns 表,以生成要发送到 UNPIVOTPIVOT 的项目列表。然后将其添加到要执行的查询字符串中。动态版本的优点是,如果您有一个不断变化的颜色和/或名称列表,这将在运行时生成该列表。

所有三个查询将产生相同的结果:

| NAME | RED | GREEN | BLUE |
-----------------------------
| Eric |   3 |     5 |    1 |
| John |   5 |     4 |    2 |
| Paul |   1 |     8 |    2 |
|  Tim |   1 |     3 |    9 |

关于sql - 在 SQL 中转置列和行的简单方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13372276/

相关文章:

mysql - 如何从mysql中具有相同别名的两个或多个表中选择数据

sql - 在SSMS中,如何找到包含星号,一些文本和另一个星号的字符串?

sql-server - 选择将 varchar 列转换为 bigint 失败的记录

mysql - 表示 er 图中 sql/mysql 的全部部分参与

php - 将sql查询的结果设置为php中if语句内的变量

sql - 不完整数据的完全外连接(通过 id 变量)

sql-server - SSIS包作业执行完成后如何查看结果?

php - PDO lastInsertId() 不适用于 MS SQL

sql-server - T-SQL 写入文件 txt 或 csv

具有多个可能连接(或连接条件)的 SQL 查询