Sql server 基于组将行转换为列
您好,我有一个场景,其中我生成了如下sql查询输出: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
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同意。但我们得到的唯一信息是他询问的结果,没有其他信息,对此,我的回答应该提供一个解决方案。此外,用包含原始查询的子查询替换表引用应该是一项简单的任务。完全同意。