我有下表:
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 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')
答案 0 :(得分:3)
无需创建两个Pivots。可以通过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
<强>返回强>
生成的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的子查询生成以下内容
答案 1 :(得分:2)
基于您的样本日期
DECLARE @Table1 TABLE
(student int, teacher varchar(7), grade varchar(1), gradedate varchar(10))
;
INSERT INTO @Table1
(student, teacher, grade, gradedate)
VALUES
(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')
;
脚本:
;WITH CTE AS (
select student, teacher,col,val,Col1,val1
from @Table1
CROSS APPLY (VALUES ('grade',grade))CS(COL,VAL)
CROSS APPLY (VALUES ('gradedate',gradedate))CSS(COL1,VAL1)
)
Select T.student,
MAX(T.ALICE) AS Alicegrade,
MAX(TT.ALICE) AS AliceDate,
MAX(T.BOB) As BobGrade,
MAX(TT.BOB) As BobDate,
MAX(T.CHARLES) AS CharlesGrade,
MAX(TT.CHARLES) As CharlesDate,
MAX(T.DAVID) As DavidGrade,
MAX(TT.DAVID) As DavidDate
from (
Select Student,
[ALICE],
[BOB],
[CHARLES],
[DAVID]
from CTE
PIVOT (MAX(VAL)
for teacher in ([ALICE],[BOB],[CHARLES],[DAVID]))PVT )T
INNER JOIN
(Select Student,
[ALICE],
[BOB],
[CHARLES],
[DAVID]
from CTE
PIVOT (MAX(VAL1) for teacher in ([ALICE],[BOB],[CHARLES],[DAVID]))PVT)TT
ON T.student = TT.student
GROUP BY T.student
答案 2 :(得分:2)
我还是喜欢好的&ol; MAX(CASE)
(由PIVOT
在后台创建),大量剪切和粘贴修改,但效率很高。
看Ma,没有加入
select student,
max(case when teacher = 'ALICE' then grade end) AS ALICEGrade,
max(case when teacher = 'ALICE' then gradedate end) AS ALICEGradeDate,
max(case when teacher = 'BOB' then grade end) AS BOBGrade,
max(case when teacher = 'BOB' then gradedate end) AS BOBGradeDate,
max(case when teacher = 'CHARLES' then grade end) AS CHARLESGrade,
max(case when teacher = 'CHARLES' then gradedate end) AS CHARLESGradeDate,
max(case when teacher = 'DAVID' then grade end) AS DAVIDGrade,
max(case when teacher = 'DAVID' then gradedate end) AS DAVIDGradeDate
from TESTGRADETABLE
group by student
答案 3 :(得分:1)
如果您有一个以上的学生教师成绩记录。我将添加解决方案。它基于@dnoeth解决方案。
SELECT student,
max(case when teacher = 'ALICE' then grade end) AS ALICEGrade,
max(case when teacher = 'ALICE' then gradedate end) AS ALICEGradeDate,
max(case when teacher = 'BOB' then grade end) AS BOBGrade,
max(case when teacher = 'BOB' then gradedate end) AS BOBGradeDate,
max(case when teacher = 'CHARLES' then grade end) AS CHARLESGrade,
max(case when teacher = 'CHARLES' then gradedate end) AS CHARLESGradeDate,
max(case when teacher = 'DAVID' then grade end) AS DAVIDGrade,
max(case when teacher = 'DAVID' then gradedate end) AS DAVIDGradeDate
FROM (
SELECT student,
teacher,
grade,
gradedate,
ROW_NUMBER() OVER(PARTITION BY teacher, student ORDER BY grade asc, gradedate desc) as ord
FROM testgradetable
) grades
WHERE ord = 1
GROUP BY student