/*有三个数据库表, 一个是学生表S(SNO,SNAME),字段分别表示学号,姓名; 一个是课程表C(CNO,CNAME),字段分别表示课程号,课程名称; 一个是成绩表T(SNO,CNO,SCORE),字段分别表示学号,课程号,该学生该课程成绩。
现在要实现这个表:
姓名 语文 数学 英语 物理 化学 ... 张三 分数 分数 分数 分数 分数 李四 分数 分数 分数 分数 分数 王五 分数 分数 分数 分数 分数 ...
*/
T-SQL
f
object_id
(
'
s
'
)
is
not
null
drop
table
s
if
object_id
(
'
c
'
)
is
not
null
drop
table
c
if
object_id
(
'
t
'
)
is
not
null
drop
table
t
create
table
S(sno
int
,sname
varchar
(
300
))
create
table
c(cno
int
,cname
varchar
(
300
))
create
table
t(sno
int
,cno
int
,score
int
)
insert
into
S(sno,sname)
select
1
,
'
张三
'
union
select
2
,
'
李四
'
union
select
3
,
'
王五
'
union
select
4
,
'
甲六
'
insert
into
c(cno,cname)
select
1
,
'
语文
'
union
select
2
,
'
数学
'
union
select
3
,
'
英语
'
union
select
4
,
'
物理
'
union
select
5
,
'
化学
'
union
select
6
,
'
历史
'
union
select
7
,
'
历史
'
insert
into
t(SNO,CNO,score)
select
1
,
1
,
80
union
select
1
,
2
,
70
union
select
1
,
3
,
50
union
select
1
,
4
,
60
union
select
1
,
5
,
90
union
select
1
,
6
,
60
union
select
2
,
1
,
41
union
select
2
,
2
,
42
union
select
2
,
3
,
53
union
select
2
,
4
,
64
union
select
3
,
1
,
43
union
select
3
,
2
,
44
union
select
3
,
3
,
55
union
select
3
,
4
,
66
/**/
/*使用动态SQL语句*/
declare
@abc
varchar
(
3000
)
set
@abc
=
''
select
@abc
=
@abc
+
'
,min( case when cno =
'
+
cast
(cno
as
varchar
(
8
))
+
'
then score end ) as
'''
+
cname
+
''''
from
c
declare
@sql
varchar
(
3000
)
set
@sql
=
'
select (select sname from S where S.sno= T.sno ) as sname
'
+
@abc
+
'
from T group by sno
'
exec
(
@sql
)
/**/
/* 不使用动态SQL语句*/
select
sname 姓名,
max
(yw) 语文,
max
(sx) 数学,
max
(yy) 英语,
max
(wl) 物理,
max
(hx) 化学,
max
(ls) 历史
from
(
select
sname ,(
case
when
cname
=
'
语文
'
then
score
end
) yw, (
case
when
cname
=
'
数学
'
then
score
end
) sx, (
case
when
cname
=
'
英语
'
then
score
end
) yy, (
case
when
cname
=
'
物理
'
then
score
end
) wl, (
case
when
cname
=
'
化学
'
then
score
end
) hx, (
case
when
cname
=
'
历史
'
then
score
end
) ls
from
t
left
join
s
on
t.sno
=
s.sno
left
join
c
on
t.cno
=
c.cno ) tmp
group
by
sname
有如图A所示的表stat,表的内容为各个班级拥有水果的数量,要求将表stat的查询结果以图B的形式显示。
class fruit amount ----------------------------- class a apple 30 class a pear 15 class b apple 40 class b pear 20 图 A
class apple_amount pear_amount ---------------------------- class a 30 15 class b 40 20 图 B
T-SQL
create
table
stat(class
varchar
(
30
), fruit
varchar
(
30
), amount
int
)
insert
into
stat (class,fruit,amount)
select
'
class a
'
,
'
apple
'
,
30
union
select
'
class a
'
,
'
pear
'
,
15
union
select
'
class b
'
,
'
apple
'
,
40
union
select
'
class b
'
,
'
pear
'
,
20
union
select
'
class a
'
,
'
apple
'
,
11
union
select
'
class b
'
,
'
apple
'
,
12
select
*
from
stat
select
class,
sum
(apple_amount) apple_amount,
sum
(pear_amount) pear_amount
from
(
select
class, (
case
when
fruit
=
'
apple
'
then
amount
else
0
end
)
as
apple_amount, (
case
when
fruit
=
'
pear
'
then
amount
else
0
end
)
as
pear_amount
from
stat ) tmp
group
by
class
PL/SQL
create
table
stat(class
varchar2
(
30
), fruit
varchar2
(
30
), amount
number
(
10
));
insert
into
stat(class, fruit, amount)
values
(
'
class a
'
,
'
apple
'
,
30
);
insert
into
stat(class, fruit, amount)
values
(
'
class a
'
,
'
pear
'
,
15
);
insert
into
stat(class, fruit, amount)
values
(
'
class b
'
,
'
apple
'
,
40
);
insert
into
stat(class, fruit, amount)
values
(
'
class b
'
,
'
pear
'
,
20
);
commit
;
select
class,
sum
(apple_amount) apple_amount,
sum
(pear_amount) pear_amount
from
(
select
class, decode(fruit,
'
apple
'
, amount,
0
) apple_amount, decode(fruit,
'
pear
'
, amount,
0
) pear_amount
from
stat )
group
by
class
存储过程
/**/
/*范例表 create table 表1 ( 號數 char(10), 成績 integer, 科目 char(10) ) insert into 表1 select '1',60,'数学' union select '1',43,'物理' union select '1',100,'语文' union select '2',87,'语文' union select '2',99,'数学' union select '2',89,'物理' union select '2',87,'语文' */
Create
procedure
RowToColumn
@Table
varchar
(
30
),
--
表名
@MasterField
varchar
(
30
),
--
待转名称列名 char字段
@SlaveField
varchar
(
30
),
--
待转数据列名 int型字段
@GroupID
varchar
(
30
)
--
分组ID
as
--
调用方法 RowToColumn '表1','科目','成績','號數'
begin
DECLARE
@mSQL
VARCHAR
(
8000
)
set
@msql
=
'
DECLARE @SQL VARCHAR(8000)
'
set
@msql
=
@msql
+
'
set @SQL=
''
select
'
+
@GroupID
+
''''
set
@msql
=
@msql
+
'
SELECT @SQL= @SQL+
''
,max(CASE WHEN
'
+
@MasterField
+
'
=
''''''
+
'
+
@MasterField
+
'
+
''''''
then
'
+
@SlaveField
+
'
else 0 end )[
''
+
'
+
@MasterField
+
'
+
''
]
''
from(select distinct
'
+
@MasterField
+
'
from
'
+
@Table
+
'
) a
'
set
@msql
=
@msql
+
'
SET @SQL=@SQL+
''
from
'
+
@Table
+
'
group by
'
+
@GroupID
+
''''
set
@msql
=
@msql
+
'
exec(@SQL)
'
exec
(
@msql
)
end
分组行转列
/**/
/*1. 表格A原始数据如下:*/
CREATE
TABLE
[
dbo
]
.
[
A
]
(
[
C1
]
[
varchar
]
(
50
) COLLATE Chinese_PRC_CS_AS
NULL
,
[
C2
]
[
varchar
]
(
50
) COLLATE Chinese_PRC_CS_AS
NULL
,
[
C3
]
[
varchar
]
(
50
) COLLATE Chinese_PRC_CS_AS
NULL
,
[
C4
]
[
varchar
]
(
50
) COLLATE Chinese_PRC_CS_AS
NULL
)
insert
into
A (
'
95533
'
,
'
SZ
'
,
'
44
'
,
'
123000
'
)
insert
into
A (
'
95566
'
,
'
SZ
'
,
'
44
'
,
'
233300
'
)
insert
into
A (
'
95588
'
,
'
GZ
'
,
'
44
'
,
'
4566
'
)
insert
into
A (
'
95599
'
,
'
GZ
'
,
'
44
'
,
'
456666
'
)
insert
into
A (
'
95533
'
,
'
ZH
'
,
'
44
'
,
'
333333
'
)
insert
into
A (
'
95577
'
,
'
DG
'
,
'
44
'
,
'
555555
'
)
insert
into
A (
'
95588
'
,
'
ST
'
,
'
44
'
,
'
44444
'
)
/**/
/*2. 分组行变列 处理数据:*/
DECLARE
@SQL
VARCHAR
(
4000
)
SET
@SQL
=
'
SELECT C2
'
SELECT
@SQL
=
@SQL
+
'
,max(CASE WHEN C1 =
'''
+
C1
+
'''
THEN C4 ELSE 0 END) [
'
+
C1
+
'
]
'
FROM
(
SELECT
DISTINCT
C1
FROM
A) TAB
SET
@SQL
=
@SQL
+
'
FROM A GROUP BY C2
'
EXEC
(
@SQL
)
/**/
/*得到如下结果: */
C2
95533
95566
95577
95588
95599
--
------------------------------------------
DG
0
0
555555
0
0
GZ
0
0
0
4566
456666
ST
0
0
0
44444
0
SZ
123000
233300
0
0
0
ZH
333333
0
0
0
0
OK, 分组就这样完成了. 参考经典实例:
/**/
/* 实例一 create table t (id int identity,name varchar(10),code int) insert t values('人口',20) insert t values('经济',12) insert t values('文化',15) insert t values('土地',45) declare @sql varchar(1000) set @sql = '' select @sql = @sql+name+'=max(case when name='''+name+''' then code else null end),' from t --print @sql set @sql = left(@sql,len(@sql) - 1) set @sql = 'select [姓名]=''年龄'', '+@sql+' from t' exec (@sql) --drop table t 实例二 create table #(a varchar(100),b int) insert # values('aa',11) insert # values('bb',1) insert # values('aa',45) insert # values('cc',81) insert # values('a',11) insert # values('aay',561) insert # values('a',14) declare @sql varchar(8000) set @sql = 'select ' select @sql = @sql + 'sum(case a when '''+a+''' then b else 0 end) '+a+'的数量,' from (select distinct a from #) as a select @sql = left(@sql,len(@sql)-1) + ' from #' exec(@sql) -- drop table # */
--行列互转
/******************************************************************************************************************************************************
以学生成绩为例子,比较形象易懂
整理人:中国风(Roy)
日期:2008.06.06
******************************************************************************************************************************************************/
--1、行互列
--> --> (Roy)生成測試數據
if not object_id('Class') is null
drop table Class
Go
Create table Class([Student] nvarchar(2),[Course] nvarchar(2),[Score] int)
Insert Class
select N'张三',N'语文',78 union all
select N'张三',N'数学',87 union all
select N'张三',N'英语',82 union all
select N'张三',N'物理',90 union all
select N'李四',N'语文',65 union all
select N'李四',N'数学',77 union all
select N'李四',N'英语',65 union all
select N'李四',N'物理',85
Go
--2000方法:
动态:
declare @s nvarchar(4000)
set @s=''
Select @s=@s+','+quotename([Course])+'=max(case when [Course]='+quotename([Course],'''')+' then [Score] else 0 end)'
from Class group by[Course]
exec('select [Student]'+@s+' from Class group by [Student]')
生成静态:
select
[Student],
[数学]=max(case when [Course]='数学' then [Score] else 0 end),
[物理]=max(case when [Course]='物理' then [Score] else 0 end),
[英语]=max(case when [Course]='英语' then [Score] else 0 end),
[语文]=max(case when [Course]='语文' then [Score] else 0 end)
from
Class
group by [Student]
GO
动态:
declare @s nvarchar(4000)
Select @s=isnull(@s+',','')+quotename([Course]) from Class group by[Course]
exec('select * from Class pivot (max([Score]) for [Course] in('+@s+'))b')
生成静态:
select *
from
Class
pivot
(max([Score]) for [Course] in([数学],[物理],[英语],[语文]))b
生成格式:
/*
Student 数学 物理 英语 语文
------- ----------- ----------- ----------- -----------
李四 77 85 65 65
张三 87 90 82 78
(2 行受影响)
*/
------------------------------------------------------------------------------------------
go
--加上总成绩(学科平均分)
--2000方法:
动态:
declare @s nvarchar(4000)
set @s=''
Select @s=@s+','+quotename([Course])+'=max(case when [Course]='+quotename([Course],'''')+' then [Score] else 0 end)'
from Class group by[Course]
exec('select [Student]'+@s+',[总成绩]=sum([Score]) from Class group by [Student]')--加多一列(学科平均分用avg([Score]))
生成动态:
select
[Student],
[数学]=max(case when [Course]='数学' then [Score] else 0 end),
[物理]=max(case when [Course]='物理' then [Score] else 0 end),
[英语]=max(case when [Course]='英语' then [Score] else 0 end),
[语文]=max(case when [Course]='语文' then [Score] else 0 end),
[总成绩]=sum([Score]) --加多一列(学科平均分用avg([Score]))
from
Class
group by [Student]
go
--2005方法:
动态:
declare @s nvarchar(4000)
Select @s=isnull(@s+',','')+quotename([Course]) from Class group by[Course] --isnull(@s+',','') 去掉字符串@s中第一个逗号
exec('select [Student],'+@s+',[总成绩] from (select *,[总成绩]=sum([Score])over(partition by [Student]) from Class) a
pivot (max([Score]) for [Course] in('+@s+'))b ')
生成静态:
select
[Student],[数学],[物理],[英语],[语文],[总成绩]
from
(select *,[总成绩]=sum([Score])over(partition by [Student]) from Class) a --平均分时用avg([Score])
pivot
(max([Score]) for [Course] in([数学],[物理],[英语],[语文]))b
生成格式:
/*
Student 数学 物理 英语 语文 总成绩
------- ----------- ----------- ----------- ----------- -----------
李四 77 85 65 65 292
张三 87 90 82 78 337
(2 行受影响)
*/
go
--2、列转行
--> --> (Roy)生成測試數據
if not object_id('Class') is null
drop table Class
Go
Create table Class([Student] nvarchar(2),[数学] int,[物理] int,[英语] int,[语文] int)
Insert Class
select N'李四',77,85,65,65 union all
select N'张三',87,90,82,78
Go
--2000:
动态:
declare @s nvarchar(4000)
select @s=isnull(@s+' union all ','')+'select [Student],[Course]='+quotename(Name,'''')--isnull(@s+' union all ','') 去掉字符串@s中第一个union all
+',[Score]='+quotename(Name)+' from Class'
from syscolumns where ID=object_id('Class') and Name not in('Student')--排除不转换的列
order by Colid
exec('select * from ('+@s+')t order by [Student],[Course]')--增加一个排序
生成静态:
select *
from (select [Student],[Course]='数学',[Score]=[数学] from Class union all
select [Student],[Course]='物理',[Score]=[物理] from Class union all
select [Student],[Course]='英语',[Score]=[英语] from Class union all
select [Student],[Course]='语文',[Score]=[语文] from Class)t
order by [Student],[Course]
go
--2005:
动态:
declare @s nvarchar(4000)
select @s=isnull(@s+',','')+quotename(Name)
from syscolumns where ID=object_id('Class') and Name not in('Student')
order by Colid
exec('select Student,[Course],[Score] from Class unpivot ([Score] for [Course] in('+@s+'))b')
go
select
Student,[Course],[Score]
from
Class
unpivot
([Score] for [Course] in([数学],[物理],[英语],[语文]))b
生成格式:
/*
Student Course Score
------- ------- -----------
李四 数学 77
李四 物理 85
李四 英语 65
李四 语文 65
张三 数学 87
张三 物理 90
张三 英语 82
张三 语文 78
(8 行受影响)
*/