Sql server 基于组将行转换为列

Sql server 基于组将行转换为列,sql-server,Sql Server,您好,我有一个场景,其中我生成了如下sql查询输出: number x1 y1 z1 x2 y2 z2 x3 y3 z3 a 1 10 aa a 2 8 aa a 3 6 aa b 4 11 bb b 5 6 bb ;WITH CTE AS (SELECT ROW_NUMBER() OVER (PARTITION BY nu

您好,我有一个场景,其中我生成了如下sql查询输出:

number  x1  y1  z1  x2  y2  z2  x3  y3  z3
 a       1  10  aa                        
 a       2   8  aa
 a       3   6  aa
 b       4   11 bb
 b       5   6  bb
;WITH CTE AS 
    (SELECT ROW_NUMBER() OVER (PARTITION BY number ORDER BY x1 asc) RN, *
    FROM TESTTABLE)
SELECT c.number, C.x1, C.y1, C.z1
    , C2.x1 as x2, C2.y1 as y2, C2.z1 as z2
    , C3.x1 as x3, C3.y1 as y3, C3.z1 as z3
FROM CTE C
LEFT JOIN CTE C2 ON C2.number = C.number AND C2.RN = 2
LEFT JOIN CTE C3 ON C3.number = C.number AND C3.RN = 3
WHERE C.RN=1
现在我被困在这里:如何将上述行转换为:

number  x1  y1  z1  x2  y2  z2  x3  y3  z3
 a       1  10  aa  2   8   aa   3   6  aa                    
 b       4  11  bb  5   6   bb
每个数字最多可以有10个x、y、z值x1、y1、z1、…、x10、y10、z10


那么如何才能做到这一点呢?

我不知道这背后的逻辑是什么,但是的,这是可以做到的

首先,我使用它来初始化作为测试集呈现的大致相同的数据:

CREATE TABLE TESTTABLE (number varchar(5), x1 varchar(5), y1 varchar(5), z1 varchar(5)
     , x2 varchar(5), y2 varchar(5), z2 varchar(5), x3 varchar(5), y3 varchar(5), z3 varchar(5))

INSERT INTO TESTTABLE (number,x1,y1,z1)
VALUES ('a','1','10','aa')
    ,('a','2','8','aa')
    ,('a','3','6','aa')
    ,('b','4','11','bb')
    ,('b','5','6','bb')
现在回答问题。。如果您对硬编码最大列数很在行,您可以这样做:

number  x1  y1  z1  x2  y2  z2  x3  y3  z3
 a       1  10  aa                        
 a       2   8  aa
 a       3   6  aa
 b       4   11 bb
 b       5   6  bb
;WITH CTE AS 
    (SELECT ROW_NUMBER() OVER (PARTITION BY number ORDER BY x1 asc) RN, *
    FROM TESTTABLE)
SELECT c.number, C.x1, C.y1, C.z1
    , C2.x1 as x2, C2.y1 as y2, C2.z1 as z2
    , C3.x1 as x3, C3.y1 as y3, C3.z1 as z3
FROM CTE C
LEFT JOIN CTE C2 ON C2.number = C.number AND C2.RN = 2
LEFT JOIN CTE C3 ON C3.number = C.number AND C3.RN = 3
WHERE C.RN=1
但是,如果您只想动态显示包含数据的列,那么类似这样的操作就可以完成这项工作。这很难看,但我唯一关心的是它能否正常工作:

DECLARE @TSQLHeader nvarchar(max) = '', @TSQLTrailer nvarchar(max) = '
FROM CTE C'

DECLARE @MaxCols INT = 
    (SELECT TOP 1 COUNT(*) CNT FROM TESTTABLE GROUP BY number ORDER BY CNT DESC)
    , @CurCol INT = 2

SELECT @TSQLHeader = 
';WITH CTE AS 
    (SELECT ROW_NUMBER() OVER (PARTITION BY number ORDER BY x1 asc) RN, *
    FROM TESTTABLE)
SELECT c.number, C.x1, C.y1, C.z1'

WHILE @CurCol <= @MaxCols
BEGIN
    SELECT @TSQLHeader = @TSQLHeader+'
    , C'+CAST(@CurCol AS VARCHAR(5))+'.x1 as x'+CAST(@CurCol AS VARCHAR(5))+', C'+CAST(@CurCol AS VARCHAR(5))+'.y1 as y'+CAST(@CurCol AS VARCHAR(5))
    +', C'+CAST(@CurCol AS VARCHAR(5))+'.z1 as z'+CAST(@CurCol AS VARCHAR(5))
    SELECT @TSQLTrailer = @TSQLTrailer+'
LEFT JOIN CTE C'+CAST(@CurCol AS VARCHAR(5))+' ON C'+CAST(@CurCol AS VARCHAR(5))+'.number = C.number AND C'+CAST(@CurCol AS VARCHAR(5))+'.RN = '+CAST(@CurCol AS VARCHAR(5))

    SET @CurCol = @CurCol+1
END 

-- Combine the header and trailer, producing a finished script
SELECT @TSQLHeader = @TSQLHeader + @TSQLTrailer+'
WHERE C.RN=1'

EXEC sp_executesql @TSQLHeader

当然,如果你的问题中有什么遗漏,为了适应任何不同的情况,必须对其进行大幅度的更改。

我曾尝试对number to number to x1不等于x2等等使用更新查询,但没有效果。我尝试使用pivot,但我不确定pivot是否适用于这种情况。您的源数据看起来如何?它是如何构造的?我相信OP已经提到,第一个数据样本实际上是他通过编写查询获得的结果。现在,他正试图解释它,而不是前3列x1,y1,z1。在这种情况下,我认为更重要的是了解源数据并在此基础上构建解决方案,而不是基于他的中间结果,因为正如您所说的,必须进行大幅更改以适应任何不同的情况。Yup同意。但我们得到的唯一信息是他询问的结果,没有其他信息,对此,我的回答应该提供一个解决方案。此外,用包含原始查询的子查询替换表引用应该是一项简单的任务。完全同意。