Sql server 使用不同表中的动态列创建查询

Sql server 使用不同表中的动态列创建查询,sql-server,tsql,pivot,Sql Server,Tsql,Pivot,我试图基于三个表中的数据创建一个具有动态列的查询 这是数据库结构: 学生 studentID int studentNumber int studentName nvarchar(100) 考试: examID int examName varchar(100) 检查日期时间 考试注册: studentID int examID int 当学生注册参加考试时,会将记录添加到考试注册表中 我想得到的是透视表中所有考试和所有学生的列表,以查看哪些学生注册了哪些考试,如下所示: 坦白说,

我试图基于三个表中的数据创建一个具有动态列的查询

这是数据库结构:

学生

  • studentID int
  • studentNumber int
  • studentName nvarchar(100)
考试:

  • examID int
  • examName varchar(100)
  • 检查日期时间
考试注册:

  • studentID int
  • examID int
当学生注册参加考试时,会将记录添加到
考试注册
表中

我想得到的是透视表中所有考试和所有学生的列表,以查看哪些学生注册了哪些考试,如下所示:

坦白说,我不知道从哪里开始

我可以单独查询所有内容并将其放在一起,但如何将其组合到一个查询中

我一直在研究pivot表,但每个示例似乎只从一个表中查询,并使用数字和函数,如
MIN
AVG

有人能帮帮我吗?

好的,我们走吧

一些数据可以使用

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)
现在是主要部分和说明

首先,您必须获得pivot查询

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
现在,只需在pivot声明中更改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的信息,请访问msdn 如果你想阅读有关dynamic的文章,请选择

编辑:要调整注释中问题的查询,您必须像这样更改@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
这是数据的轴心。我会执行与其他答案稍有不同的操作。如果您知道所有的值,那么您可以硬编码这些值

静态版本将是:

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  |

一个学生有可能参加两次考试吗?不,那将是一次新安排的考试。太好了,让某些东西发挥作用的缺点是:管理层想要更多p现在我的主管要求更改它,因此输出如下:。我不知道你是否注意到我在这篇文章中添加了一个关于你第二个问题的编辑,只要告诉我这是否是你想要的,你只需要更改@sqlcolumnlist是的,我只是在看这个。谢谢:)