Sql server 2008 SQL Server 2008-透视表
我正在尝试对我的表进行透视,以将行作为列输出。 我在网上看到了一些例子,但每次解释到否定时,我都会迷路(我认为这与我想要实现的目标无关?)。我有下面的课程表:Sql server 2008 SQL Server 2008-透视表,sql-server-2008,pivot,pivot-table,Sql Server 2008,Pivot,Pivot Table,我正在尝试对我的表进行透视,以将行作为列输出。 我在网上看到了一些例子,但每次解释到否定时,我都会迷路(我认为这与我想要实现的目标无关?)。我有下面的课程表: StudentID ClassCode 10001 ENG240 10001 MTH100 10001 BIO101 10001 HUM300 10002 PHY200 10002 PHY200-L 1000
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
我想要得到的是以下输出:
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
pivot字段最多只能有五列。如果有学生有五个以上的课程,则应向结果集中添加新记录
有谁能告诉我一个实现这一目标的好方法吗?
太多了
*编辑:*
现在,我可以使用下面的查询透视表:
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
我现在需要做的是如何限制只有5条记录应该垂直旋转。如果学生的班级超过5个,则应添加第二个记录
谢谢大家 通过实现两个窗口函数,
ntile()
和row\u number()
,您可以轻松获得结果
将用于将您的数据划分为“bucket”,因此当您使用NTILE(5)
时,您将为每个StudentId
的classcode
创建5个bucket
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass;
看。这会将您的数据转换为以下格式:
| STUDENTID | CLASSCODE | NEWCOL |
|-----------|-----------|------------|
| 10002 | CHR100 | ClassCode1 |
| 10002 | COM140 | ClassCode1 |
| 10002 | HUM200 | ClassCode2 |
| 10002 | MTH100 | ClassCode3 |
| 10002 | PHY200 | ClassCode4 |
| 10002 | PHY200-L | ClassCode5 |
正如您可以看到的,数据现在在5个存储桶中,这些存储桶是您的新列名ClassCode1
,ClassCode2
,等等。您还将注意到有两行ClassCode1
,如果现在应用PIVOT函数,您将只返回一行。为了返回多行,您需要对数据应用row\u 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;
看。这将得到以下结果:
| 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 |
| 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) |
相同的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;
看
如果您想使用聚合函数和您在问题中遇到的CASE表达式,那么您仍然可以使用NTILE()
和row\u 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;
看。两个版本都将给出以下最终结果:
| 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 |
| 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) |
由于只有5列,因此不需要使用动态SQL来获得结果。通过实现两个窗口函数,
ntile()
和row\u number()
可以轻松获得结果
将用于将您的数据划分为“bucket”,因此当您使用NTILE(5)
时,您将为每个StudentId
的classcode
创建5个bucket
select StudentId, ClassCode,
newCol =
'ClassCode' +
cast(ntile(5) over(partition by StudentId
order by ClassCode) as varchar(1))
from TestClass;
看。这会将您的数据转换为以下格式:
| STUDENTID | CLASSCODE | NEWCOL |
|-----------|-----------|------------|
| 10002 | CHR100 | ClassCode1 |
| 10002 | COM140 | ClassCode1 |
| 10002 | HUM200 | ClassCode2 |
| 10002 | MTH100 | ClassCode3 |
| 10002 | PHY200 | ClassCode4 |
| 10002 | PHY200-L | ClassCode5 |
正如您可以看到的,数据现在在5个存储桶中,这些存储桶是您的新列名ClassCode1
,ClassCode2
,等等。您还将注意到有两行ClassCode1
,如果现在应用PIVOT函数,您将只返回一行。为了返回多行,您需要对数据应用row\u 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;
看。这将得到以下结果:
| 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 |
| 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) |
相同的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;
看
如果您想使用聚合函数和您在问题中遇到的CASE表达式,那么您仍然可以使用NTILE()
和row\u 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;
看。两个版本都将给出以下最终结果:
| 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 |
| 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) |
由于您只有5列,因此不需要使用动态SQL来获得结果。到目前为止您尝试了什么,以及将类代码放在ClassCode1、2、3下的逻辑是什么???你好这是我需要输出的报告。基本上,客户机需要的是一个在页面上垂直显示类的报告。到目前为止,我已经能够做到这一点。但是,我仍然需要关于如何将最大列设置为5以及如何在类超过5的情况下创建另一行记录的帮助。请看我的编辑上面。非常感谢。到目前为止,您尝试了什么?将类代码放在ClassCode1、2、3…下的逻辑是什么???你好这是我需要输出的报告。基本上,客户机需要的是一个在页面上垂直显示类的报告。到目前为止,我已经能够做到这一点。但是,我仍然需要关于如何将最大列设置为5以及如何在类超过5的情况下创建另一行记录的帮助。请看我的编辑上面。非常感谢。你好非常感谢这个!!!我有一个快速跟进的问题。如果我决定添加另一个名为SectionCode的列,该列与类代码有一定的1:1对应关系,该怎么办?这会如何影响表的轴呢?我能够使用
NTILE()
函数输出带有类代码的SectionCode。但我有点迷路了。非常感谢你!!!!没关系,我可以通过调整你的代码使它工作!非常感谢!19小时后给你赏金。(由于某些原因,系统现在不允许我授予它)非常感谢!!!!!!!!!!!!!!!!你好非常感谢这个!!!我有一个快速跟进的问题。如果我决定添加另一个名为SectionCode的列,该列与类代码有一定的1:1对应关系,该怎么办?这会如何影响表的轴呢?我能够使用NTILE()
函数输出带有类代码的SectionCode。但我有点迷路了。非常感谢你!!!!没关系,我可以通过调整你的代码使它工作!谢谢