sql - 分组和切换列和行

标签 sql sql-server t-sql pivot sql-server-2012

我不知道这是否会被正式称为枢轴,但我想要的结果是这样的:

+------+---------+------+
| Alex | Charley | Liza |
+------+---------+------+
|  213 |     345 |    1 |
|   23 |     111 |    5 |
|   42 |      52 |    2 |
|  323 |         |    5 |
|   23 |         |    1 |
|  324 |         |    5 |
+------+---------+------+

我的输入数据采用以下形式:

+-----+---------+
| Apt |  Name   |
+-----+---------+
| 213 | Alex    |
|  23 | Alex    |
|  42 | Alex    |
| 323 | Alex    |
|  23 | Alex    |
| 324 | Alex    |
| 345 | Charley |
| 111 | Charley |
|  52 | Charley |
|   1 | Liza    |
|   5 | Liza    |
|   2 | Liza    |
|   5 | Liza    |
|   1 | Liza    |
|   5 | Liza    |
+-----+---------+

因为我有大约 100 个名称,所以我不想像这样执行大量子查询

select null, null, thirdcolumn from...
select null, seconcolumn from...
select firstcolumn from...

有没有办法通过PIVOT或其他方式来做到这一点?

最佳答案

您可以使用动态 PIVOTROW_NUMBER() 函数来完成此操作:

DECLARE @cols AS VARCHAR(1000),
        @query  AS VARCHAR(8000)
SELECT @cols = STUFF((SELECT ',' +   QUOTENAME(Name) 
                    FROM (SELECT DISTINCT Name
                          FROM #test
                          )sub
                    ORDER BY Name
                    FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)') 
                    ,1,1,'')
PRINT @cols

SET @query = '
WITH cte AS (SELECT DISTINCT *
             FROM  #test)
    ,cte2 AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Apt)RowRank
             FROM  cte)
SELECT * 
FROM  cte2 
PIVOT (max(Apt) for Name in ('+@cols+')) p
            '
EXEC (@query)

SQL Fiddle - Distinct List, Specific Order

编辑:如果您不希望列表不同,请消除上面的第一个 cte,如果您想保持任意顺序,请将 ORDER BY 更改为 (SELECT 1) :

DECLARE @cols AS VARCHAR(1000),
        @query  AS VARCHAR(8000)
SELECT @cols = STUFF((SELECT ',' +   QUOTENAME(Name) 
                    FROM (SELECT DISTINCT Name
                          FROM #test
                          )sub
                          ORDER BY Name
                    FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)') 
                    ,1,1,'')
PRINT @cols

SET @query = '
WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY (SELECT 1))RowRank
             FROM  #test)
SELECT * 
FROM  cte 
PIVOT (max(Apt) for Name in ('+@cols+')) p
            '
EXEC (@query)

SQL Fiddle - Full List, Arbitrary Order

最后,如果您不想在结果中包含 RowRank 字段,只需在 SELECT 中重复使用 @cols 变量即可>:

SET @query = '
WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY (SELECT 1))RowRank
             FROM  #test)
SELECT '+@cols+' 
FROM  cte 
PIVOT (max(Apt) for Name in ('+@cols+')) p
            '
EXEC (@query)

关于sql - 分组和切换列和行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18282758/

相关文章:

mysql - 如何在 sp_executesql 中使用来自其他存储过程的输入参数

sql - 无法将临时表从一个存储过程传递到另一个存储过程,出现错误 'Must declare scalar variable'

SQL Server 2008 - 如何将 GMT(UTC) 日期时间转换为本地日期时间?

sql - 如何计算 Oracle SQL 中计数列的总和?

sql-server - 如何与多个 CTE 联合?

sql - 如何将WITH (NOLOCK) 应用于整个查询

sql - 如何将日期时间值从行转换为列

SQL - 另一个 Select 语句的 Where 子句?

mysql - 对所有基于文本的字段使用通用 varchar(255) 是否有缺点?

sql - 对象名称无效,但对象显然有效