如何在sql中将行转换为列
Posted
技术标签:
【中文标题】如何在sql中将行转换为列【英文标题】:How to convert rows into column in sql 【发布时间】:2016-08-29 08:39:20 【问题描述】:我有一张桌子,
并需要将其转换为
我已经尝试过枢轴但无法弄清楚请帮助我。
【问题讨论】:
您是否有固定数量的要合并的行?否则,我建议将数据解析为数组 是的,我需要修改 ID 代码和员工姓名 @shakedzy 你没有回答这个问题。每个 ID 的行数是否固定? 不,这不是固定的@shakedzy Convert Rows to columns using 'Pivot' in SQL Server的可能重复 【参考方案1】:Pivot 不能处理多个列开箱即用有几种方法可以解决这个问题:
将此表变量用于所有测试,并请说明您的示例数据始终可复制“n”粘贴。最好的是一个 MCVE(最小完整可验证示例),您可以在其中设置一些类似我的代码。
DECLARE @tbl TABLE(ID INT, Code INT,EmployeeName VARCHAR(100),ExamName VARCHAR(100),Board VARCHAR(100),Result VARCHAR(100));
INSERT INTO @tbl VALUES
(11537,12984,'TheName','SSC','b04','1st')
,(11537,12984,'TheName','HSC','b04','2nd')
,(11537,12984,'TheName','BA(H)','u33','2nd');
这是首先将您的数据连接到一列的代码。这允许PIVOT
:
SELECT p.*
FROM
(
SELECT tbl.ID
,tbl.Code
,tbl.EmployeeName
,'Exam_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS VARCHAR(100)) AS ColName
,ExamName + ' (' + Board + '): ' + Result AS Concatenated
FROM @tbl AS tbl
) AS t
PIVOT
(
MIN(Concatenated) FOR ColName IN(Exam_1,Exam_2,Exam_3 /*add as many as you need*/)
) AS p
结果:
11537 12984 TheName SSC (b04): 1st HSC (b04): 2nd BA(H) (u33): 2nd
下一个代码的作用完全一样,但创建的是 XML 而不是纯文本,这允许之后分离您的数据:
SELECT p.ID
,p.Code
,p.EmployeeName
,E1
,E1.value('(/exam/@ExamName)[1]','varchar(100)') AS ExamName1
,E1.value('(/exam/@Board)[1]','varchar(100)') AS Board1
,E1.value('(/exam/@Result)[1]','varchar(100)') AS Result1
,E2
,E2.value('(/exam/@ExamName)[1]','varchar(100)') AS ExamName2
,E2.value('(/exam/@Board)[1]','varchar(100)') AS Board2
,E2.value('(/exam/@Result)[1]','varchar(100)') AS Result2
,E3
,E3.value('(/exam/@ExamName)[1]','varchar(100)') AS ExamName3
,E3.value('(/exam/@Board)[1]','varchar(100)') AS Board3
,E3.value('(/exam/@Result)[1]','varchar(100)') AS Result3
FROM
(
SELECT tbl.ID
,tbl.Code
,tbl.EmployeeName
,'Exam_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS VARCHAR(100)) AS ColName
,(SELECT ExamName AS [@ExamName],Board AS [@Board],Result AS [@Result] FOR XML PATH('exam')) AS AsXML
FROM @tbl AS tbl
) AS t
PIVOT
(
MIN(AsXML) FOR ColName IN(Exam_1,Exam_2,Exam_3 /*add as many as you need*/)
) AS p
OUTER APPLY
(
SELECT CAST(p.Exam_1 AS XML) AS E1
,CAST(p.Exam_2 AS XML) AS E2
,CAST(p.Exam_3 AS XML) AS E3
) AS CastedToXml
结果:
11537 12984 TheName <exam ExamName="SSC" Board="b04" Result="1st" /> SSC b04 1st <exam ExamName="HSC" Board="b04" Result="2nd" /> HSC b04 2nd <exam ExamName="BA(H)" Board="u33" Result="2nd" /> BA(H) u33 2nd
这是 old-fashioned-pivot,通常比正常的枢轴要好:
;WITH Numberd AS
(
SELECT *
,ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS Number
FROM @tbl AS tbl
)
SELECT ID,Code,EmployeeName
,MAX(CASE WHEN Number=1 THEN ExamName END) AS ExamName1
,MAX(CASE WHEN Number=1 THEN Board END) AS Board1
,MAX(CASE WHEN Number=1 THEN Result END) AS Result1
,MAX(CASE WHEN Number=2 THEN ExamName END) AS ExamName2
,MAX(CASE WHEN Number=2 THEN Board END) AS Board2
,MAX(CASE WHEN Number=2 THEN Result END) AS Result2
,MAX(CASE WHEN Number=3 THEN ExamName END) AS ExamName3
,MAX(CASE WHEN Number=3 THEN Board END) AS Board3
,MAX(CASE WHEN Number=3 THEN Result END) AS Result3
FROM Numberd
GROUP BY ID,Code,EmployeeName
最后一个选项是动态 SQL...
【讨论】:
【参考方案2】:谢谢大家,但是我的目的已经解决了
SELECT
he.Id,he.Code,he.Name EmployeeName,en.Name [ExamName],bu.Name
[Board],[Result] = CASE WHEN
ac.GPA IS NULL THEN ac.Result ELSE CAST(ac.GPA AS VARCHAR) END,
ac.PassingYear
INTO #Temp
FROM H_Employee AS he
INNER JOIN
H_AcademicQualification AS ac ON ac.H_EmployeeId = he.Id
INNER JOIN
ExamName AS en ON en.Id = ac.ExamNameId
INNER JOIN
GroupSubject AS gs ON gs.Id = ac.GroupSubjectId
INNER JOIN
BoardUniversity AS bu ON bu.Id = ac.BoardUniversityId
然后
SELECT
a.id, a.Code, a.EmployeeName, a.ExamName, a.Board, a.Result, a.Passingyear,
b.ExamName, b.Board, b.Result, b.Passingyear,
c.ExamName, c.Board, c.Result, c.Passingyear,
d.ExamName, d.Board, d.Result, d.Passingyear
FROM
(SELECT
Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'S.S.%' THEN 'S.S.C' END,
Board=Board ,[Result]=CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'S.S.%') AS a
LEFT JOIN
(SELECT Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'H.S.%' THEN 'H.S.C' END,
Board=Board,[Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'H.S.%') AS b
ON a.Id=b.Id
LEFT JOIN
(SELECT Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'B.%' THEN 'Graduate' END,
Board=Board, [Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'B.%') AS c
ON a.Id=c.Id
LEFT JOIN
(SELECT Id, Code, EmployeeName, ExamName = CASE WHEN
ExamName LIKE 'M.%' THEN 'Post-Graduate' END,
Board=Board,[Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'M.%') AS d
ON a.Id=d.Id
以上查询为我服务,但会尝试@Shnugo Sample,无论如何谢谢大家。
【讨论】:
很高兴您自己找到了答案。如果您检查我的代码并且它对您有用,最好接受它作为答案,首先关闭此问题,其次帮助未来的访问者找到实际问题的答案,第三:这会为您和我的帐户:-)以上是关于如何在sql中将行转换为列的主要内容,如果未能解决你的问题,请参考以下文章