我正在尝试根据来自三个表的数据创建一个包含动态列的查询。
这是数据库结构:
学生
studentID int
,studentNumber int
,studentName nvarchar(100)
。EXAM:
examID int
,examName varchar(100)
,examenDate datetime
,EXAM_REGISTRATION:
studentID int
,examID int
,当学生注册考试时,会在EXAM_REGISTRATION
表格中添加记录。
我想要得到的是所有考试和所有学生在数据透视表中的列表,以查看哪些学生已注册哪些考试,如下所示:
坦率地说,我不知道从哪里开始。
我可以单独查询所有内容并将它们放在一起但是如何将它组合成一个查询?
我一直在研究数据透视表,但每个示例似乎只从一个表中查询并使用数字和函数,如MIN
,AVG
等。
有人可以帮助我吗?
答案 0 :(得分:1)
好吧,让我们走吧
要播放的一些数据
create table #student
(studentID int, studentNumber int, studentName nvarchar(100))
create table #exam
(examID int, examName nvarchar(100), examDate datetime)
create table #examReg
(studentID int, examID int)
insert into #student
values (1, 787878, 'pierwszy')
,(2, 89898, 'drugi')
,(3, 343434, 'trzeci')
,(4, 121212, 'czwarty')
insert into #exam
values (1, 'exPierwszy', GETDATE())
,(2, 'exDrugi', GETDATE())
,(3, 'exTrzeci', GETDATE())
insert into #examReg
values (1,2),(1,3)
, (2,2),(2,3)
,(3,1),(3,2)
,(4,1),(4,2),(4,3)
现在是主要部分和解释
首先,您必须获得透视查询
select examName, examDate , min([1]) , min([2]), min([3]) ,min([4])--studentID as studentID, examDate --,studentNumber
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in ([1],[2],[3],[4])) as t
group by examName, examDate
如你所知,只需在枢轴声明中更改它的select语句和studentID列表,就必须动态生成这些部分,所以我们只需复制以前编写的查询并用我们的令牌替换列
declare @sqlTemplate nvarchar(max) =
'select examName, examDate @@sqlColumnList@@
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in (@@sqlStudentIDList@@)) as t
group by examName, examDate
'
之后,通过在tsql中连接字符串来生成列列表和studentID列表
declare @sqlColumnList nvarchar(max) = ''
select @sqlColumnList += ',min([' + cast(studentID as nvarchar(10)) + ']) as [' + studentName +'(' + cast(studentNumber as nvarchar(10)) + ')]'
from #student
declare @sqlStudentIDList nvarchar(max) = ''
select @sqlStudentIDList += '[' + CAST(studentID as nvarchar(10)) + '],'
from #student
set @sqlStudentIDList = SUBSTRING(@sqlStudentIDList, 0, LEN(@sqlStudentIDList))
select @sqlStudentIDList
一旦拥有它,您所要做的就是替换先前模板中的令牌
set @sqlTemplate = REPLACE(@sqlTemplate, '@@sqlColumnList@@', @sqlColumnList)
set @sqlTemplate = REPLACE(@sqlTemplate, '@@sqlStudentIDList@@', @sqlStudentIDList)
select @sqlTemplate
exec sp_executesql @sqlTemplate
就是这样 如果你想了解更多关于pivot go for msdn的信息 如果你想阅读关于动态去this link
编辑:要根据评论调整问题的查询,你必须更改@sqlColumnList
select @sqlColumnList += ',min(' + QUOTENAME(studentID) + ') as Student' + CAST(studentID as nvarchar(10)) + '_REG,
'''+ studentName + ''' as Student' + cast(studentID as nvarchar(10)) + '_NAME,
'+ cast(studentID as nvarchar(10)) + ' as Student' + cast(studentID as nvarchar(10)) + '_ID'
from #student
答案 1 :(得分:0)
这是数据的 pivot 。我会执行与其他答案略有不同的操作。如果您知道所有值,那么您可以对值进行硬编码。
静态版本将是:
select examname,
examendate,
IsNull([Smith, John (14323)], 'false') [Smith, John (14323)],
IsNull([Craft, Peter (14334)], 'false') [Craft, Peter (14334)],
IsNull([Davis, Alan (13432)], 'false') [Davis, Alan (13432)],
IsNull([Newman, Ted (133123)], 'false') [Newman, Ted (133123)]
from
(
select e.examname,
e.examenDate,
s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')' studentNameNum,
'true ' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) src
pivot
(
max(flag)
for studentNameNum in ([Smith, John (14323)], [Craft, Peter (14334)],
[Davis, Alan (13432)], [Newman, Ted (133123)])
) piv
如果您的值未知,则查询将为:
DECLARE @cols AS NVARCHAR(MAX),
@colsNull AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsNull = STUFF((SELECT distinct ',IsNull(' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')+', ''false'')'+' as '+QUOTENAME(s.studentName+' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT examname,
examenDate,' + @colsNull + ' from
(
select e.examname,
e.examenDate,
s.studentName + '' (''+cast(s.studentnumber as varchar(50))+'')'' studentNameNum,
''true '' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) x
pivot
(
max(flag)
for studentNameNum in (' + @cols + ')
) p '
execute(@query)
结果将是:
| EXAMNAME | EXAMENDATE | CRAFT, PETER (14334) | DAVIS, ALAN (13432) | NEWMAN, TED (133123) | SMITH, JOHN (14323) |
----------------------------------------------------------------------------------------------------------------------------
| Exam 1 | 2013-01-01 12:00:00 | false | false | true | false |
| Exam 2 | 2013-01-01 14:00:00 | true | false | false | true |
| Exam 3 | 2013-01-02 12:00:00 | true | true | false | false |
| Exam 4 | 2013-01-02 14:00:00 | false | false | true | false |
| Exam 5 | 2013-01-03 12:00:00 | false | false | false | true |