如何在 SQL Server 2008 中将行更改为列(多个表、联接等)
How to change rows into columns in SQL Server 2008 (multiple tables, joins etc)
我需要帮助创建调查应用程序的报告。
主要涉及5张表:
- 调查(ID,ReportColumnName)
- 栏目(ID、栏目名称)
- Surveys_Sections(FK_Surveys, FK_Sections, 有效)
- Sections_Surveys_ScoreValues (FK_Surveys, FK_Sections, FK_ScoreCategories, SectionScoreValue)
- ScoreCategories(ID、ScoreStart、ScoreEnd、CategoryName)
每次创建调查时,都会生成一个新的 ReportColumnName
,它需要成为报告中的一个列。对于这些列中的每一列,以及每个部分(在调查中处于活动状态),都会有一个 SectionScoreValue
。这进一步链接并检查它是否在 ScoreCategories
的间隔内,并为每个调查和部分显示结果类别 (CategoryName
)。
几天来我一直在寻找如何正确旋转这些列并正确显示所需值的方法。通过对从网站上获得的一些代码进行改编,我认为这会起作用:
declare @SQL nvarchar(max), @Cols nvarchar(max)
select @Cols =
stuff(
(
select ', ' + quotename(dt)
from
(
select TOP 100 PERCENT Sv.ID, Sv.ReportColumnName as dt
from Surveys AS Sv
ORDER BY Sv.ID
) X
ORDER BY X.ID FOR XML PATH('')
),1,1,''
)
SELECT @Cols
set @SQL =
'SELECT Sv.ReportColumnName, SSSV.*
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
PIVOT (max(SSSV.SectionScoreValue) FOR Sv.ReportColumnName IN (' + @Cols
+')) pvt'
execute (@sql)
@Cols
变量包含我需要的列(即调查的名称)并正确显示它们(并以逗号分隔)。所以这部分工作正常。
我的问题是下一部分应该(最初)为每个 SectionName
(在第一列)和每个调查(每个单独的调查)放置 SectionScoreValue
列)。
这些调查列是在创建新列时动态添加的,因此它们从来都不是一个常数。
这些表中的每一个都有一个默认为 GetDATE()
的 CreateDate
列。我得到的错误是:
The column 'CreateDate' was specified multiple times for 'pvt'.
The multi-part identifier "Sv.ReportColumnName" could not be bound.
The column prefix 'SSSV' does not match with a table name or alias name used in the query.
请帮助正确显示我的数据。它应该显示如下内容:
Section Survey1 Survey2 Survey3 ......
s1 1.33 1.66 2.5
s2 0.00 3.33 4
s3 2.33 2 1.66
s4 0.66 2.5 3
数字也可以替换为 ScoreCategoryName 中的值(如 'Good'、'Excellent' 等,根据数字所在的区间)。
谢谢
编辑 1:这就是 PRINT @SQL
的结果:
SELECT Sv.ReportColumnName, SSSV.*
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
PIVOT (max(SSSV.SectionScoreValue) FOR Sv.ReportColumnName
IN ( [S1-1-2 -3], [S217], [al 3], [S37], [R4], [ult_nume_col])) pvt
编辑 2: 感谢 Giorgi,我设法找到了解决方案!这是最终代码,它显示了我所需要的列:
declare @SQL nvarchar(max), @Cols nvarchar(max)
select @Cols =
stuff(
(
select ', ' + quotename(dt)
from
(
select TOP 100 PERCENT Sv.ID, Sv.ReportColumnName as dt
from Surveys AS Sv
ORDER BY Sv.ID
) X
ORDER BY X.ID FOR XML PATH('')
),1,1,''
)
SELECT @Cols
SET @SQL = ';
WITH cte
AS ( SELECT Sv.CreateDate, Sv.ReportColumnName, Sc.SectionName, SSSV.SectionScoreValue
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
)
SELECT SectionName , ' + @Cols + '
FROM cte PIVOT ( MAX(cte.SectionScoreValue) FOR cte.ReportColumnName IN (' + @Cols + ') ) pvt'
print @sql
execute (@sql)
感谢大家的帮助,感谢 "vote down"(如果我能自己得到结果,我就不会在这里发布)。
旋转拨号时始终使用 table 表达式。像这样:
SET @SQL = ';
WITH cte
AS ( SELECT SSSV.SectionScoreValue ,
Sv.ReportColumnName ,
Section
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS ON SS.FK_Surveys_ID = Sv.ID AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
)
SELECT Section , ' + @Cols + '
FROM cte PIVOT ( MAX(SSSV.SectionScoreValue) FOR Sv.ReportColumnName IN (' + @Cols + ') ) pvt'
也可以看看我对类似问题的回答:
我需要帮助创建调查应用程序的报告。 主要涉及5张表:
- 调查(ID,ReportColumnName)
- 栏目(ID、栏目名称)
- Surveys_Sections(FK_Surveys, FK_Sections, 有效)
- Sections_Surveys_ScoreValues (FK_Surveys, FK_Sections, FK_ScoreCategories, SectionScoreValue)
- ScoreCategories(ID、ScoreStart、ScoreEnd、CategoryName)
每次创建调查时,都会生成一个新的 ReportColumnName
,它需要成为报告中的一个列。对于这些列中的每一列,以及每个部分(在调查中处于活动状态),都会有一个 SectionScoreValue
。这进一步链接并检查它是否在 ScoreCategories
的间隔内,并为每个调查和部分显示结果类别 (CategoryName
)。
几天来我一直在寻找如何正确旋转这些列并正确显示所需值的方法。通过对从网站上获得的一些代码进行改编,我认为这会起作用:
declare @SQL nvarchar(max), @Cols nvarchar(max)
select @Cols =
stuff(
(
select ', ' + quotename(dt)
from
(
select TOP 100 PERCENT Sv.ID, Sv.ReportColumnName as dt
from Surveys AS Sv
ORDER BY Sv.ID
) X
ORDER BY X.ID FOR XML PATH('')
),1,1,''
)
SELECT @Cols
set @SQL =
'SELECT Sv.ReportColumnName, SSSV.*
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
PIVOT (max(SSSV.SectionScoreValue) FOR Sv.ReportColumnName IN (' + @Cols
+')) pvt'
execute (@sql)
@Cols
变量包含我需要的列(即调查的名称)并正确显示它们(并以逗号分隔)。所以这部分工作正常。
我的问题是下一部分应该(最初)为每个 SectionName
(在第一列)和每个调查(每个单独的调查)放置 SectionScoreValue
列)。
这些调查列是在创建新列时动态添加的,因此它们从来都不是一个常数。
这些表中的每一个都有一个默认为 GetDATE()
的 CreateDate
列。我得到的错误是:
The column 'CreateDate' was specified multiple times for 'pvt'.
The multi-part identifier "Sv.ReportColumnName" could not be bound.
The column prefix 'SSSV' does not match with a table name or alias name used in the query.
请帮助正确显示我的数据。它应该显示如下内容:
Section Survey1 Survey2 Survey3 ......
s1 1.33 1.66 2.5
s2 0.00 3.33 4
s3 2.33 2 1.66
s4 0.66 2.5 3
数字也可以替换为 ScoreCategoryName 中的值(如 'Good'、'Excellent' 等,根据数字所在的区间)。
谢谢
编辑 1:这就是 PRINT @SQL
的结果:
SELECT Sv.ReportColumnName, SSSV.*
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
PIVOT (max(SSSV.SectionScoreValue) FOR Sv.ReportColumnName
IN ( [S1-1-2 -3], [S217], [al 3], [S37], [R4], [ult_nume_col])) pvt
编辑 2: 感谢 Giorgi,我设法找到了解决方案!这是最终代码,它显示了我所需要的列:
declare @SQL nvarchar(max), @Cols nvarchar(max)
select @Cols =
stuff(
(
select ', ' + quotename(dt)
from
(
select TOP 100 PERCENT Sv.ID, Sv.ReportColumnName as dt
from Surveys AS Sv
ORDER BY Sv.ID
) X
ORDER BY X.ID FOR XML PATH('')
),1,1,''
)
SELECT @Cols
SET @SQL = ';
WITH cte
AS ( SELECT Sv.CreateDate, Sv.ReportColumnName, Sc.SectionName, SSSV.SectionScoreValue
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV
ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc
ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS
ON SS.FK_Surveys_ID = Sv.ID
AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC
ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
)
SELECT SectionName , ' + @Cols + '
FROM cte PIVOT ( MAX(cte.SectionScoreValue) FOR cte.ReportColumnName IN (' + @Cols + ') ) pvt'
print @sql
execute (@sql)
感谢大家的帮助,感谢 "vote down"(如果我能自己得到结果,我就不会在这里发布)。
旋转拨号时始终使用 table 表达式。像这样:
SET @SQL = ';
WITH cte
AS ( SELECT SSSV.SectionScoreValue ,
Sv.ReportColumnName ,
Section
FROM Surveys AS Sv
INNER JOIN Sections_Surveys__ScoreValues AS SSSV ON SSSV.FK_Surveys_ID = Sv.ID
INNER JOIN Sections AS Sc ON Sc.ID = SSSV.FK_Sections_ID
INNER JOIN Sections_Surveys AS SS ON SS.FK_Surveys_ID = Sv.ID AND SS.FK_Sections_ID = Sc.ID
INNER JOIN ScoreCategories AS ScoreC ON ScoreC.ID = SSSV.FK_ScoreCategories_ID
)
SELECT Section , ' + @Cols + '
FROM cte PIVOT ( MAX(SSSV.SectionScoreValue) FOR Sv.ReportColumnName IN (' + @Cols + ') ) pvt'
也可以看看我对类似问题的回答: