Smi*_*ley 1 pivot pivot-table sql-server-2008
我试图在我的表上做一个Pivot输出行作为列.我已经在互联网上看到了一些例子,但是每次解释到达聚合时我都迷失了(我认为这与我想要达到的目标无关?).我有以下类表:
StudentID ClassCode
10001 ENG240
10001 MTH100
10001 BIO101
10001 HUM300
10002 PHY200
10002 PHY200-L
10002 MTH100
10002 HUM200
10002 CHR100
10002 COM140
10003 HUM100
10003 ENG200
10003 PHY101
Run Code Online (Sandbox Code Playgroud)
我想得到的是以下输出:
StudentID ClassCode 1 ClassCode 2 ClassCode 3 ClassCode 4 ClassCode 5
10001 ENG240 MTH100 BIO101 HUM300
10002 PHY200 PHY200-L MTH100 HUM200 CHR100
10002 COM140
10003 HUM100 ENG200 PHY101
Run Code Online (Sandbox Code Playgroud)
枢轴字段最多只能是五列.如果有超过五个班级的学生,则应将新记录添加到结果集中.
任何人都可以请我指出一个很好的方法来实现这一目标吗?Thakns这么多!
*编辑:*
到目前为止,我可以使用下面的查询来旋转表格:
CREATE
TABLE #TestClass
(StudentID INT, row INT, ClassCode VARCHAR(32))
;WITH TCSPivot(StudentID, row, ClassCode)
AS
(SELECT StudentID,
row_number() OVER(PARTITION BY StudentID ORDER BY StudentID, ClassCode),
ClassCode
FROM student_class
)
INSERT
INTO #TestClass
SELECT p.StudentID,
p.row,
p.ClassCode
FROM MyPivot p
JOIN class c
ON c.ClassCode = p.ClassCode
SELECT @sql = @sql + ', MAX(CASE WHEN row = ' + CAST(tc.row AS CHAR(5)) + ' THEN ClassCode ELSE '''' END) AS [ClassCode ' + CAST(tc.row AS CHAR(5)) + ']'
FROM #TestClass tc
GROUP
BY tc.row
ORDER
BY tc.row
SET @sql = @sql + N'
FROM #TestClass
GROUP
BY StudentID
ORDER
BY StudentID'
EXEC sp_executesql @sql
Run Code Online (Sandbox Code Playgroud)
我现在需要做的是如何限制只有5条记录应该垂直旋转.如果存在类别大于5的StudentID,则应添加第二条记录.
感谢大家!!
您可以轻松地实现2个窗函数得到的结果,ntile()和row_number().
NTILE()将用于将您的数据划分为"存储桶",因此在您使用时NTILE(5),您ClassCodes将为每个存储创建5个存储桶StudentId.
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo.这将使您的数据格式为:
| STUDENTID | CLASSCODE | NEWCOL |
|-----------|-----------|------------|
| 10002 | CHR100 | ClassCode1 |
| 10002 | COM140 | ClassCode1 |
| 10002 | HUM200 | ClassCode2 |
| 10002 | MTH100 | ClassCode3 |
| 10002 | PHY200 | ClassCode4 |
| 10002 | PHY200-L | ClassCode5 |
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,数据现在位于5个桶中,这些桶是您的新列名ClassCode1,ClassCode2等等.您还会注意到有两行ClassCode1,如果您应用PIVOT函数,现在只返回一行.要返回多行,您需要应用于row_number()数据.
该row_number()会为每一行数据的唯一序列:
;with cte as
(
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass
),
mr as
(
select StudentId, ClassCode,
newCol,
row_number() over(partition by StudentId, newCol order by newCol) seq
from cte
)
select *
from mr;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo.这得到了以下结果:
| STUDENTID | CLASSCODE | NEWCOL | SEQ |
|-----------|-----------|------------|-----|
| 10002 | CHR100 | ClassCode1 | 1 |
| 10002 | COM140 | ClassCode1 | 2 |
| 10002 | HUM200 | ClassCode2 | 1 |
| 10002 | MTH100 | ClassCode3 | 1 |
| 10002 | PHY200 | ClassCode4 | 1 |
| 10002 | PHY200-L | ClassCode5 | 1 |
Run Code Online (Sandbox Code Playgroud)
现在NewCol相同的值ClassCode1具有不同的序列号.在数据透视过程中按数据分组时需要这样做.
最后,您可以应用该PIVOT函数来获得最终结果:
;with cte as
(
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass
),
mr as
(
select StudentId, ClassCode,
newCol,
row_number() over(partition by StudentId, newCol order by newCol) seq
from cte
)
select studentid,
ClassCode1, ClassCode2, ClassCode3,
ClassCode4, ClassCode5
from mr
pivot
(
max(ClassCode)
for NewCol in (ClassCode1, ClassCode2, ClassCode3,
ClassCode4, ClassCode5)
) piv
order by StudentId;
Run Code Online (Sandbox Code Playgroud)
如果你想像你在问题中那样使用带有CASE表达式的聚合函数,那么你仍然会使用NTILE(),row_number()但最终的代码是:
;with cte as
(
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass
),
mr as
(
select StudentId, ClassCode,
newCol,
row_number() over(partition by StudentId, newCol order by newCol) seq
from cte
)
select studentid,
max(case when newcol = 'ClassCode1' then ClassCode end) ClassCode1,
max(case when newcol = 'ClassCode2' then ClassCode end) ClassCode2,
max(case when newcol = 'ClassCode3' then ClassCode end) ClassCode3,
max(case when newcol = 'ClassCode4' then ClassCode end) ClassCode4,
max(case when newcol = 'ClassCode5' then ClassCode end) ClassCode5
from mr
group by StudentId, seq
order by StudentId;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo.两个版本都将给出最终结果:
| STUDENTID | CLASSCODE1 | CLASSCODE2 | CLASSCODE3 | CLASSCODE4 | CLASSCODE5 |
|-----------|------------|------------|------------|------------|------------|
| 10001 | BIO101 | ENG240 | HUM300 | MTH100 | (null) |
| 10002 | CHR100 | HUM200 | MTH100 | PHY200 | PHY200-L |
| 10002 | COM140 | (null) | (null) | (null) | (null) |
| 10003 | ENG200 | HUM100 | PHY101 | (null) | (null) |
Run Code Online (Sandbox Code Playgroud)
由于您只有5列,因此不需要使用动态SQL来获取结果.
| 归档时间: |
|
| 查看次数: |
260 次 |
| 最近记录: |