【转】纵表、横表互转的SQL |
您所在的位置:网站首页 › 数据竖向转横向 › 【转】纵表、横表互转的SQL |
方法二:--用case when 实现SELECT T.NAME, SUM(CASE T.Course WHEN '语文' THEN T.Score ELSE 0 END) 语文, SUM(CASE T.Course WHEN '数学' THEN T.Score ELSE 0 END) 数学, SUM(CASE T.Course WHEN '英语' THEN T.Score ELSE 0 END) 英语 FROM T_T_STUDENT TGROUP BY T.NAME
输出结果如下: 姓名 语文 数学 英语1 刘备 90 94 922 关羽 97 53 953 张飞 80 87 68
区别如果条件是单一值时,用decode比较简便,如果判断条件比较复杂是用case when实现
--------------------
普通行列转换假设有张学生成绩表(tb)如下:Name Subject Result张三 语文 74张三 数学 83张三 物理 93李四 语文 74李四 数学 84李四 物理 94*/ -------------------------------------------------------------------------/*想变成 姓名 语文 数学 物理 ---------- ----------- ----------- ----------- 李四 74 84 94张三 74 83 93*/ create table tb( Name varchar(10) , Subject varchar(10) , Result int) insert into tb(Name , Subject , Result) values('张三' , '语文' , 74)insert into tb(Name , Subject , Result) values('张三' , '数学' , 83)insert into tb(Name , Subject , Result) values('张三' , '物理' , 93)insert into tb(Name , Subject , Result) values('李四' , '语文' , 74)insert into tb(Name , Subject , Result) values('李四' , '数学' , 84)insert into tb(Name , Subject , Result) values('李四' , '物理' , 94)go --静态SQL,指subject只有语文、数学、物理这三门课程。select name 姓名, max(case subject when '语文' then result else 0 end) 语文, max(case subject when '数学' then result else 0 end) 数学, max(case subject when '物理' then result else 0 end) 物理from tbgroup by name/*姓名 语文 数学 物理 ---------- ----------- ----------- ----------- 李四 74 84 94张三 74 83 93*/ --动态SQL,指subject不止语文、数学、物理这三门课程。declare @sql varchar(8000)set @sql = 'select Name as ' + '姓名'select @sql = @sql + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'from (select distinct Subject from tb) as aset @sql = @sql + ' from tb group by name'exec(@sql) /*姓名 数学 物理 语文 ---------- ----------- ----------- ----------- 李四 84 94 74张三 83 93 74*/ -------------------------------------------------------------------/*加个平均分,总分姓名 语文 数学 物理 平均分 总分 ---------- ----------- ----------- ----------- -------------------- ----------- 李四 74 84 94 84.00 252张三 74 83 93 83.33 250*/ --静态SQL,指subject只有语文、数学、物理这三门课程。select name 姓名, max(case subject when '语文' then result else 0 end) 语文, max(case subject when '数学' then result else 0 end) 数学, max(case subject when '物理' then result else 0 end) 物理, cast(avg(result*1.0) as decimal(18,2)) 平均分, sum(result) 总分from tbgroup by name/*姓名 语文 数学 物理 平均分 总分 ---------- ----------- ----------- ----------- -------------------- ----------- 李四 74 84 94 84.00 252张三 74 83 93 83.33 250*/ --动态SQL,指subject不止语文、数学、物理这三门课程。declare @sql1 varchar(8000)set @sql1 = 'select Name as ' + '姓名'select @sql1 = @sql1 + ' , max(case Subject when ''' + Subject + ''' then Result else 0 end) [' + Subject + ']'from (select distinct Subject from tb) as aset @sql1 = @sql1 + ' , cast(avg(result*1.0) as decimal(18,2)) 平均分,sum(result) 总分 from tb group by name'exec(@sql1) /*姓名 数学 物理 语文 平均分 总分 ---------- ----------- ----------- ----------- -------------------- ----------- 李四 84 94 74 84.00 252张三 83 93 74 83.33 250*/ drop table tb ------------------------------------------------------------------------------------------------------------------/*如果上述两表互相换一下:即 姓名 语文 数学 物理张三 74 83 93李四 74 84 94 想变成 Name Subject Result ---------- ------- ----------- 李四 语文 74李四 数学 84李四 物理 94张三 语文 74张三 数学 83张三 物理 93*/ create table tb1( 姓名 varchar(10) , 语文 int , 数学 int , 物理 int) insert into tb1(姓名 , 语文 , 数学 , 物理) values('张三',74,83,93)insert into tb1(姓名 , 语文 , 数学 , 物理) values('李四',74,84,94) select * from( select 姓名 as Name , Subject = '语文' , Result = 语文 from tb1 union all select 姓名 as Name , Subject = '数学' , Result = 数学 from tb1 union all select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1) torder by name , case Subject when '语文' then 1 when '数学' then 2 when '物理' then 3 when '总分' then 4 end --------------------------------------------------------------------/*加个平均分,总分Name Subject Result ---------- ------- -------------------- 李四 语文 74.00李四 数学 84.00李四 物理 94.00李四 平均分 84.00李四 总分 252.00张三 语文 74.00张三 数学 83.00张三 物理 93.00张三 平均分 83.33张三 总分 250.00*/ select * from( select 姓名 as Name , Subject = '语文' , Result = 语文 from tb1 union all select 姓名 as Name , Subject = '数学' , Result = 数学 from tb1 union all select 姓名 as Name , Subject = '物理' , Result = 物理 from tb1 union all select 姓名 as Name , Subject = '平均分' , Result = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb1 union all select 姓名 as Name , Subject = '总分' , Result = 语文 + 数学 + 物理 from tb1) torder by name , case Subject when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when'总分' then 5 end drop table tb1 -------------- 动态列转行----------------新建测试表CREATE TABLE tmp_user_2(USER_ID NUMBER,MODE_NAME VARCHAR2(100),TYPE_ID NUmBER); ----------------第一部分测试数据INSERT INTO tmp_user_2 VALUES(1001, 'M1',1); INSERT INTO tmp_user_2 VALUES(1001, 'M2',2);INSERT INTO tmp_user_2 VALUES(1002, 'M1',3);INSERT INTO tmp_user_2 VALUES(1002, 'M2',4);INSERT INTO tmp_user_2 VALUES(1002, 'M3',5);INSERT INTO tmp_user_2 VALUES(1003, 'M1',6);COMMIT; ----------------行转列存储过程CREATE OR REPLACE PROCEDURE P_tmp_user_2 IS V_SQL VARCHAR2(2000); CURSOR CURSOR_1 IS SELECT DISTINCT T.MODE_NAME FROM tmp_user_2 T ORDER BY MODE_NAME; BEGIN V_SQL := 'SELECT USER_ID'; FOR V_XCLCK IN CURSOR_1 LOOP V_SQL := V_SQL || ',' || 'SUM(DECODE(MODE_NAME,''' || V_XCLCK.MODE_NAME || ''',TYPE_ID,0)) AS ' || V_XCLCK.MODE_NAME; END LOOP; V_SQL := V_SQL || ' FROM tmp_user_2 GROUP BY USER_ID'; --DBMS_OUTPUT.PUT_LINE(V_SQL); V_SQL := 'CREATE OR REPLACE VIEW tmp_user_3 AS ' || V_SQL; --DBMS_OUTPUT.PUT_LINE(V_SQL); EXECUTE IMMEDIATE V_SQL;END; ----------------执行存储过程BEGIN P_tmp_user_2; END; ----------------查看结果SELECT * FROM tmp_user_3; ----------------第二部分测试数据INSERT INTO tmp_user_2 VALUES(1003, 'M2',7); INSERT INTO tmp_user_2 VALUES(1004, 'M5',8); COMMIT; ----------------执行存储过程BEGIN P_tmp_user_2; END;----------------查看结果SELECT * FROM tmp_user_3; ---------------- 其他 : 一、横表和纵表 横表:通常指我们平时在数据库中建立的表,是一种普通的建表方式。 (主键、字段1、字段2......)如:时间、客户ID,基本通话费、漫游通话费,国内长途费、国际长途费....。 纵表:一般不多见,在表结构不确定的时候,如需增加字段的情况下的一种建表方式。 二、执行效率 横表:后台数据库管理员操作简单,直观,清晰可见,一目了然。但若要给横表中添加一个或者多个字段,就须重建表结构。 纵表:对于横表的弊端,纵表中只需要添加一条记录,就可以添加一个字段,所消耗的代价远比横表小。但是纵表的对于数据描述不是很清晰,而且会造成数据库数量很多。在查询的时候用到group等函数会大大降低执行效率。纵表的初始映射要慢一些,纵表的变更的映射可能要快一些,如果只是改变了单个字段时,毕竟横表字段比纵表要多很多。 三、转换 1.在平时的开发过程中,可能会遇到字段的添加或者更好的维护和管理大数据量的表,就 会涉及到纵表和横表之间的转换。 2.把不容易改动表结构的设计成横表,把容易经常改动不确定的表结构设计成纵表。 举例: 注:DECODE函数是ORACLE PL/SQL的功能强大的函数之一,目前还只有ORACLE公司的SQL提供了此函数,DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示如果value等于if1时,DECODE函数的结果返回then1,...,如果不等于任何一个if值,则返回else。 sign函数:在数学和计算机运算中,其功能是取某个数的符号(正或负): 当x≥0,sign(x)=1; 当x |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |