sql - 枢轴以避免 SQL 中的大量连接?

标签 sql tsql pivot sql-server-2014

我有下表:

student teacher grade   gradedate
--------------------------------------
1       ALICE   A       05.08.2016
1       BOB     A       25.01.2015
1       CHARLES C       12.05.2017
1       DAVID   B       25.09.2013
2       BOB     D       01.02.2014
2       CHARLES A       26.04.2016
2       DAVID   C       02.05.2016

(student,teacher)是这张表的主键。

我想生成这样的结果

student ALICEGrade  ALICEGradeDate  BOBGrade    BOBGradeDate    CHARLESGrade    CHARLESGradeDate    DAVIDGrade  DAVIDGradeDate
-----------------------------------------------------------------------------------------------------------------------------------------------------------
1       A           05.08.2016      A           25.01.2015      C               12.05.2017          B           25.09.2013
2       NULL        NULL            D           01.02.2014      A               26.04.2016          C           02.05.2016

我设法通过为每位教师使用 join 子句来生成它:

SELECT st.student, 
a.grade as [ALICEGrade], a.gradedate as [ALICEGradeDate], 
b.grade as [BOBGrade], b.gradedate as [BOBGradeDate],
c.grade as [CHARLESGrade], c.gradedate as [CHARLESGradeDate],
d.grade as [DAVIDGrade], d.gradedate as [DAVIDGradeDate] 
FROM
(SELECT distinct [student] FROM [dbo].[TESTGRADETABLE]) st
LEFT join [dbo].[TESTGRADETABLE] a on a.teacher = 'ALICE' and a.student = st.student 
LEFT join [dbo].[TESTGRADETABLE] b on b.teacher = 'BOB' and b.student = st.student 
LEFT join [dbo].[TESTGRADETABLE] c on c.teacher = 'CHARLES' and c.student = st.student
LEFT join [dbo].[TESTGRADETABLE] d on d.teacher = 'DAVID' and d.student = st.student

但我想知道是否有另一种更优雅的解决方案来避免大量连接(真正的请求有大约 10 个连接)。我正在考虑从以下位置开始使用数据透视表:

SELECT * FROM [dbo].[TESTGRADETABLE] 
pivot
(
    max(grade)
    for  teacher in ([ALICE],[BOB],[CHARLES],[DAVE])
) piv1

但是我被困在这里了。我不知道是否可以用它生成 TeacherGradeDate 列。

创建表和数据的TSQL:

CREATE TABLE [dbo].[TESTGRADETABLE](
    [student] [int] NOT NULL,
    [teacher] [varchar](50) NOT NULL,
    [grade] [char](1) NOT NULL,
    [gradedate] [date] NOT NULL,
 CONSTRAINT [PK_TESTGRADETABLE] PRIMARY KEY CLUSTERED 
(
    [student] ASC,
    [teacher] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

INSERT INTO dbo.[TESTRATINGTABLE]
           ([student]
           ,[teacher]
           ,[grade]
           ,[gradedate])
     VALUES
           (1,'ALICE','A','2016-08-05'),
           (1,'BOB','A','2015-01-25'),
           (1,'CHARLES','C','2017-05-12'),
           (1,'DAVID','B','2013-09-25'),           
           (2,'BOB','D','2014-02-01'),
           (2,'CHARLES','A','2016-04-26'),
           (2,'DAVID','C','2016-05-02')

最佳答案

无需创建两个枢轴。可以通过 Dynamic Pivot 实现预期的结果。

示例

Declare @SQL varchar(max) = '
Select *
 From (
        Select B.*
         From  YourTable A
         Cross Apply (values (student,teacher+''Grade'',cast(grade as varchar(max)))
                            ,(student,teacher+''GradeDate'' ,cast(gradedate as varchar(max)))
                     ) B (student,item,value)
      ) A
 Pivot (max([Value]) For [Item] in (' + Stuff((Select Distinct ','+QuoteName(concat(teacher,'Grade')) 
                                                              +','+QuoteName(concat(teacher ,'GradeDate')) 
                                               From YourTable  
                                               Order By 1 
                                               For XML Path('')),1,1,'')  + ') ) p'
Exec(@SQL);
--Print @SQL

返回

enter image description here

生成的 SQL 如下所示:

Select *
 From (
        Select B.*
         From  YourTable A
         Cross Apply (values (student,teacher+'Grade',cast(grade as varchar(max)))
                            ,(student,teacher+'GradeDate' ,cast(gradedate as varchar(max)))
                     ) B (student,item,value)
      ) A
 Pivot (max([Value]) For [Item] in ([ALICEGrade],[ALICEGradeDate],[BOBGrade],[BOBGradeDate],[CHARLESGrade],[CHARLESGradeDate],[DAVIDGrade],[DAVIDGradeDate]) ) p

“提供”PIVOT 生成以下内容的子查询

enter image description here

关于sql - 枢轴以避免 SQL 中的大量连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45215381/

相关文章:

SQL从WebMatrix Razor语法中的一个POST将数据插入多个表

php - 如果输入有 html,则清理用户输入

sql - 是否可以向临时表添加索引? create #t 和 declare @t 有什么区别

mysql - 在 mysql 中实现某种枢轴

sql - 如果组合键为 null,则填充先前的值 如果没有值则填充 null

sql - Count、Having 和 Case 语句

sql-server - 如果表存在,如何删除它?

sql-server - T-SQL Where 子句 Case 语句优化(StoredProc 的可选参数)

pandas - 如何旋转 pandas 数据框?

java - 从三个项目的中位数中选择Pivot QuickSort(JAVA)