在sql中使用pivot的多行

Posted

技术标签:

【中文标题】在sql中使用pivot的多行【英文标题】:Multiple rows using pivot in sql 【发布时间】:2020-10-05 09:10:03 【问题描述】:

我有一张桌子。

Item  | ID
--------------
1-A   | 213
2-B   | 432
3-C   | 267
3-C   | 879
3-C   | 467

我使用枢轴。

Select * from (
    Select ID,Item
    From data1
)R
Pivot (
    Max(ID) For Item 
    in 
    ([1-A],[2-B],[3-C])
)as pvt

但我只能得到一个值。

1-A  | 2-B | 3-C
-----------------
213  | 453 | 467

怎样才能得到3-C的所有值,希望能得到这个结果。

1-A  | 2-B | 3-C | 3-C | 3-C
---------------------------
213  | 453 | 267 | 879 | 467

但是3-C,可能有一个或多个,我无法控制会出现多少个。

希望能帮忙解答,谢谢。

【问题讨论】:

可以有多少行,总是5行吗?当所述行的 Item 具有相同的值(因为它显然不是 ID)时,是什么决定了所述行的顺序,还是顺序无关紧要? 目前只有3-C会有多个,至少有一个,最多有多个,也就是3-C会有多个情况 “最多”? Many 不是数字。这是否意味着行数不确定?我在评论中问的其余部分呢? 是的,行数不定,顺序无所谓。如果可以的话,希望能按照我的结果显示 【参考方案1】:

这里真正的问题是行数无法确定。这意味着您需要动态 SQL,下一个问题是您没有唯一的值可以作为枢轴,因此我们还需要对ROW_NUMBER 进行创新。这给出了这个,它不是特别漂亮,但“有效”。

CREATE TABLE dbo.YourTable (Item char(3),
                            ID int);
INSERT INTO dbo.YourTable (Item,
                           ID)
VALUES('1-A',213),
      ('2-B',432),
      ('3-C',267),
      ('3-C',879),
      ('3-C',467);
GO

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

DECLARE @Delimiter nvarchar(30) = N',' + @CRLF + N'       ';

WITH RNs AS(
    SELECT Item,
           ID,
           ROW_NUMBER() OVER (ORDER BY Item) AS RN
    FROM dbo.YourTable)
SELECT @SQL = N'WITH RNs AS(' + @CRLF +
              N'    SELECT Item,' + @CRLF +
              N'           ID,' + @CRLF +
              N'           ROW_NUMBER() OVER (ORDER BY Item) AS RN' + @CRLF +
              N'    FROM dbo.YourTable)' + @CRLF +
              N'SELECT ' +
              STRING_AGG(CONCAT(N'MAX(CASE WHEN Item = ',QUOTENAME(R.Item,''''),N' AND RN = ',R.RN,N' THEN R.ID END) AS ',QUOTENAME(R.Item)),@Delimiter) WITHIN GROUP (ORDER BY R.Item, R.RN) + @CRLF + 
              N'FROM RNs R;'
FROM RNs R;

PRINT @SQL;
EXEC sys.sp_executesql @SQL;

GO

DROP TABLE dbo.YourTable;

假设您使用的是最新版本的 SQL Server。如果不是,您需要将 STRING_AGG 替换为旧的 FOR XML PATH 方法。

DB<>Fiddle

【讨论】:

【参考方案2】:

您需要使用Dynamic SQL,因为您的列数未知。查询是动态形成的,使用sp_executesql 执行查询

看起来您想要 ItemID 组合的独特值,所以我在这里使用 GROUP BY Item, ID

declare @sql nvarchar(max)

SELECT @sql = isnull(@sql + ',', 'SELECT ')
            + CONVERT(VARCHAR(10), ID) + ' AS ' + QUOTENAME(Item)
FROM   data1
GROUP BY Item, ID
ORDER BY Item, ID

-- PRINT @sql
exec sp_executesql @sql

例如:dbfiddle

【讨论】:

你好像输了一排;你有 5 列,但在小提琴中有 6 行。 2 行是相同的。我怀疑 OP 想要重复的项目和 ID 值。特意添加它来说明这一点。【参考方案3】:

另一种方法是将结果放在3-C 值的单个列中,使用string_agg()

select string_agg(case when item = '[1-A]' then id end, ',') within group (order by id) as id_1_a,
       string_agg(case when item = '[2-B]' then id end, ',') within group (order by id) as id_2_b,
       string_agg(case when item = '[3-C]' then id end, ',') within group (order by id) as id_3_c
from data1;

这不是您指定的确切结果集,但它可能会满足您的需求。

【讨论】:

以上是关于在sql中使用pivot的多行的主要内容,如果未能解决你的问题,请参考以下文章

SQL Pivot选择多行

在excel中使用pivot时聚合多行[duplicate]

在 T-SQL 中将多行转换为具有多列的一行

SQL - 多行到列 - 枢轴?交叉表?

如何在sql中使用pivot到多列

PIVOT/UNPIVOT 多行多列