`

sql 行转列 简单易懂

阅读更多
摘自:http://blog.csdn.net/xys_777/archive/2010/06/22/5685953.aspx

阅:经验证,可运行;

行转列问题总结 - 1、行转列 (后面不断整理论坛中出现的各类问题)

---1、最简单的行转列
/*   

问题:假设有张学生成绩表(tb)如下:
姓名 课程 分数
张三 语文 74
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94


想变成(得到如下结果):
姓名 语文 数学 物理
李四 74   84   94
张三 74   83   93
*/
--测试用
IF OBJECT_ID('[tb]') IS NOT NULL DROP TABLE [tb]
GO
create table tb(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
insert into tb values('张三' , '语文' , 74)
insert into tb values('张三' , '数学' , 83)
insert into tb values('张三' , '物理' , 93)
insert into tb values('李四' , '语文' , 74)
insert into tb values('李四' , '数学' , 84)
insert into tb values('李四' , '物理' , 94)
go

--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
declare @sql varchar(8000)
set @sql = 'select 姓名 '
select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
from (select distinct 课程 from tb) as a
set @sql = @sql + ' from tb group by 姓名'
exec(@sql)
--通过动态构建@sql,得到如下脚本
select 姓名 as 姓名 ,
  max(case 课程 when '语文' then 分数 else 0 end) 语文,
  max(case 课程 when '数学' then 分数 else 0 end) 数学,
  max(case 课程 when '物理' then 分数 else 0 end) 物理
from tb
group by 姓名

--SQL SERVER 2005 动态SQL。
declare @sql varchar(8000)
select @sql = isnull(@sql + '],[' , '') + 课程 from tb group by 课程
set @sql = '[' + @sql + ']'
exec ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b')
--得到SQL SERVER 2005 静态SQL。
select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b

--查询结果
/*
姓名         数学          物理          语文         
---------- ----------- ----------- -----------
李四         84          94          74
张三         83          93          74

(所影响的行数为 2 行)
*/


--2 加合计
/*
问题:在上述结果的基础上加平均分,总分,得到如下结果:
姓名 语文 数学 物理 平均分 总分
---- ---- ---- ---- ------ ----
李四 74   84   94   84.00  252
张三 74   83   93   83.33  250
*/

--SQL SERVER 2000 静态SQL。
select 姓名 姓名,
  max(case 课程 when '语文' then 分数 else 0 end) 语文,
  max(case 课程 when '数学' then 分数 else 0 end) 数学,
  max(case 课程 when '物理' then 分数 else 0 end) 物理,
  cast(avg(分数*1.0) as decimal(18,2)) 平均分,
  sum(分数) 总分
from tb
group by 姓名

--SQL SERVER 2000 动态SQL。
declare @sql varchar(8000)
set @sql = 'select 姓名 '
select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
from (select distinct 课程 from tb) as a
set @sql = @sql + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'
exec(@sql)

--SQL SERVER 2005 静态SQL。
select m.* , n.平均分 , n.总分 from
(select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b) m,
(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
where m.姓名 = n.姓名

--SQL SERVER 2005 动态SQL。
declare @sql varchar(8000)
select @sql = isnull(@sql + ',' , '') + 课程 from tb group by 课程
exec ('select m.* , n.平均分 , n.总分 from
(select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b) m ,
(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
where m.姓名 = n.姓名')

其他实例

http://topic.csdn.net/u/20100708/18/55df5a90-27a7-4452-a69a-27f735539a1f.html?seed=24842417&r=66831902#r_66831902


--3、不同数据按照序号转为列,方法基本同 1

if object_id('tb1') is not null drop table tb1
go
CREATE table tb1 --数据表
(
cpici varchar(10) not null,
cname varchar(10) not null,
cvalue int null
)
--插入测试数据
INSERT INTO tb1 values('T501','x1',31)
INSERT INTO tb1 values('T501','x1',33)
INSERT INTO tb1 values('T501','x1',5)

INSERT INTO tb1 values('T502','x1',3)
INSERT INTO tb1 values('T502','x1',22)
INSERT INTO tb1 values('T502','x1',3)

INSERT INTO tb1 values('T503','x1',53)
INSERT INTO tb1 values('T503','x1',44)
INSERT INTO tb1 values('T503','x1',50)
INSERT INTO tb1 values('T503','x1',23)


--在sqlserver2000里需要用自增辅助
alter table tb1 add id int identity
go
declare @s varchar(8000)
set @s='select cpici '
select @s=@s+',max(case when rn='+ltrim(rn)+' then cvalue end) as cvlue'+ltrim(rn)
from (select distinct rn from (select rn=(select count(1) from tb1 where cpici=t.cpici and id<=t.id) from tb1 t)a)t
set @s=@s+' from (select rn=(select count(1) from tb1 where cpici=t.cpici and id<=t.id),* from tb1 t
) t group by cpici'

exec(@s)
go
alter table tb1 drop column id

--再2005就可以用row_number
declare @s varchar(8000)
set @s='select cpici '
select @s=@s+',max(case when rn='+ltrim(rn)+' then cvalue end) as cvlue'+ltrim(rn)
from (select distinct rn from (select rn=row_number()over(partition by cpici order by getdate()) from tb1)a)t
set @s=@s+' from (select rn=row_number()over(partition by cpici order by getdate()),* from tb1
) t group by cpici'

exec(@s)

---结果
/*
cpici      cvlue1      cvlue2      cvlue3      cvlue4
---------- ----------- ----------- ----------- -----------
T501       31          33          5           NULL
T502       3           22          3           NULL
T503       53          44          50          23
警告: 聚合或其他 SET 操作消除了空值。

(3 行受影响)

*/


--测试用
IF OBJECT_ID('[tb]') IS NOT NULL DROP TABLE [tb]
GO
create table tb(电话号码 varchar(15), 通话时长 int ,行业 varchar(10))
insert tb
select '13883633601', 10 ,'餐饮' union all
select '18689704236', 20 ,'物流' union all
select '13883633601', 20 ,'物流' union all
select '13883633601', 20 ,'汽车' union all
select '18689704236', 20 ,'医疗' union all
select '18689704236', 20 ,'it' union all
select '18689704236', 20 ,'汽车' union all
select '13883633601', 50 ,'餐饮'
go

declare @sql varchar(8000)
set @sql='select 电话号码,sum(通话时长) 通话总和'
select @sql=@sql+',max(case when rowid='+ltrim(rowid)+' then 行业 else '''' end) as [行业'+ltrim(rowid)+']'
from (select distinct rowid from (select (select count(distinct 行业) from tb where 电话号码=t.电话号码 and 行业<=t.行业) rowid
from tb t) a) b
set @sql=@sql+' from ( select * , (select count(distinct 行业) from tb where 电话号码=t.电话号码 and 行业<=t.行业) rowid
from tb t ) t group by 电话号码'
exec(@sql)

--结果
/*

(所影响的行数为 8 行)

电话号码            通话总和        行业1        行业2        行业3        行业4       
--------------- ----------- ---------- ---------- ---------- ----------
13883633601     100         餐饮         汽车         物流        
18689704236     80          it         汽车         物流         医疗

(所影响的行数为 2 行)

*/

另一种动态行转列:

http://topic.csdn.net/u/20100612/10/4CFCB667-89FA-4985-90D5-B8A420A6FF12.html

if object_id('[tb]') is not null drop table [tb]
go  
create table [tb]([姓名] varchar(1),[部门] varchar(4),[学历] varchar(4),[出生年月] datetime)
insert [tb]
select 'A','后勤','高中','1986-1-1' union all
select 'B','后勤','初中','1984-3-7' union all
select 'C','管理','本科','1987-2-1' union all
select 'D','操作','专科','1976-2-1' union all
select 'E','操作','专科','1943-2-1'  
go


GO
if object_id('GetGroupByCol') is not null drop proc GetGroupByCol
go
create  PROCEDURE [dbo].[GetGroupByCol]
@colm nvarchar(100)
  AS
declare @sql varchar(4000)

set @sql='
declare @sql varchar(8000)
set @sql=''select 部门''
select @sql =@sql+ '', sum(case ltrim('+@colm+') when ''''''+ltrim(' + @colm + ')+'''''' then 1 else 0 end)
[''+ltrim(' + @colm + ')+'']'' from (select distinct '+@colm+' from tb where '+@colm+' is not null) as a
set @sql = @sql + '' from tb group by 部门''
exec(@sql)'

exec(@sql)
GO

exec GetGroupByCol N'学历'
exec GetGroupByCol N'出生年月'
exec GetGroupByCol N'姓名'

/*

(所影响的行数为 5 行)

部门   本科          初中          高中          专科         
---- ----------- ----------- ----------- -----------
操作   0           0           0           2
管理   1           0           0           0
后勤   0           1           1           0

(所影响的行数为 3 行)

部门   02  1 1943 12:00AM 02  1 1976 12:00AM 03  7 1984 12:00AM 01  1 1986 12:00AM 02  1 1987 12:00AM
---- ------------------ ------------------ ------------------ ------------------ ------------------
操作   1                  1                  0                  0                  0
管理   0                  0                  0                  0                  1
后勤   0                  0                  1                  1                  0

(所影响的行数为 3 行)

部门   A           B           C           D           E          
---- ----------- ----------- ----------- ----------- -----------
操作   0           0           0           1           1
管理   0           0           1           0           0
后勤   1           1           0           0           0

(所影响的行数为 3 行)
*/


以下可参考的例子

1、普通多表联合

http://topic.csdn.net/u/20100623/00/077055eb-784d-4b27-8407-2c17adc06c60.html?seed=81934135&r=66426155#r_66426155

http://topic.csdn.net/u/20100622/19/9710803c-441b-45d0-b010-703a2633fe89.html?47161

2、多表根据时间 计算序号
http://topic.csdn.net/u/20100623/12/bbb0921b-0e1b-4435-8e85-959d87844954.html?seed=2145286087&r=66438763#r_66438763
http://topic.csdn.net/u/20100701/09/1684649b-b893-463b-8b40-7f4b894cd41e.html?seed=205688256&r=66630774#r_66630774

3、财务相关
http://topic.csdn.net/u/20100626/00/83499112-43ae-4caa-a1fd-268cc5138da6.html?seed=415671352&r=66513615#r_66513615

4、根据行数转列

http://topic.csdn.net/u/20100705/12/e325571b-c368-4174-859f-17ae708eca3d.html

http://topic.csdn.net/u/20100706/09/c34728dc-6167-45df-b7cf-974612b9aa8b.html

http://topic.csdn.net/u/20100706/16/f217deed-a2be-4950-b911-2624ac7a881a.html?39445

5、根据排序大小转

http://topic.csdn.net/u/20100707/13/63f4a02e-ebc3-4c71-9380-d6b2ca0eb366.html?39970

6、分组排序按序号转

http://topic.csdn.net/u/20100725/05/7f813114-c423-4759-97b8-b22e1e2e90d7.html?seed=471594449&r=67220945#r_67220945



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xys_777/archive/2010/06/22/5685953.aspx
分享到:
评论

相关推荐

    SQL 2005 列转行的方法

    SQL列转行的方法 介绍的是两种列转行的方法。简单易懂...

    简单易懂的sql安全设置和基础

    简单易懂的sql安全设置和基础 规律:数字不用单引号,字符用单引号 选择 1. 假设有一个名为email_table 的表,包含名字和地址两个字段,要得到Bill Gates 的e_mail地址,你可以使用下面的查询: SELECT email from ...

    SQL语法大全

    SQL语法大全 SQL语法大全 1. ASP与Access数据库连接: dim conn,mdbfile mdbfile=server.mappath("数据库名称.mdb") set conn=server.createobject("adodb.connection") conn.open "driver={microsoft access ...

    精通SQL 结构化查询语言详解

    8.3.2 GROUP BY子句根据多列组合行  8.3.3 ROLLUP运算符和CUBE运算符  8.3.4 GROUP BY子句中的NULL值处理  8.3.5 HAVING子句  8.3.6 HAVING子句与WHERE子句  8.3.7 SELECT语句各查询子句总结  第9章 ...

    SQL.Server.2008编程入门经典(第3版).part2.rar

    作者Robert Vieria是Microsoft SQL,Server方面的权威,他采用通俗易懂的方法揭示了SQL Server-2008核心组件的重要更改。 《SQL Server 2008编程入门经典(第3版)》首先概述了数据库设计的概念,介绍了如何用SQL Set...

    SQL性能优化

     实际大部分应用中是不会产生重复的记录,推荐采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。  Exists 示例:当有 A、B 两个结果集,当结果集 B 很大时,A 较小时,适用 ...

    SQL.Server.2008编程入门经典(第3版).part1.rar

    作者Robert Vieria是Microsoft SQL,Server方面的权威,他采用通俗易懂的方法揭示了SQL Server-2008核心组件的重要更改。 《SQL Server 2008编程入门经典(第3版)》首先概述了数据库设计的概念,介绍了如何用SQL Set...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 第一章 Oracle入门 一、 数据库概述 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它产生于距今五十年前。简单来说是本身可视...

    倒序逐条删除表中数据

    利用存储过程倒序逐条删除表中数据,对于表中有自链接id的时候很管用哦。代码量少且简单易懂。

    物业管理系统源码Delphi+SQL

    使得各项费用的计算、统计、汇总工作简单方便,轻松自如。 自动控制各项费用收缴,保证公司收益:管理费用的收缴是管理公司能够正常运营的保证。通过客户自觉缴费和人工催费,往往效率较低,难以应付。计算机管理可...

    Java web 期末大作业,完成度100%附带文档.

    系统管理操作简单易懂 3.1 总体结构 3.2 模块详情 学生模块: 注册: 1. 用户点击注册,进行注册; 2. 用户输入注册信息; 3. 校验数据:如果用户名重复或者两次密码校验不合格或者密码规格不符合,则提示错误信息...

    C#程序开发范例宝典(第2版).part13

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part08

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part02

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part12

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

Global site tag (gtag.js) - Google Analytics