您的位置:首页 > 数据库 > Oracle

Oracle中实现行列转换的方法

2007-09-26 11:04 806 查看
们在写SQL语句的时候经常需要用到行与列的转换问题,对于一个新手来说可能比较困难,其实你只要能够熟练运用Decode和Sum函数,这个问题就迎刃而解.

Create table test (name char(10),km char(10),cj Number)

insert into test values('张三','语文',80)
insert into test values('张三','数学',86)
insert into test values('张三','英语',75)
insert into test values('李四','语文',78)
insert into test values('李四','数学',85)
insert into test values('李四','英语',78)

commit;

怎样实现成这样:
name 语文 数学 英语
李四 78 85 83
张三 80 86 75

16:03:50 SQL> select * from test;

NAME KM CJ
---------- ---------- ----------
张三 语文 80
张三 数学 86
张三 英语 75
李四 语文 78
李四 数学 85
李四 英语 78

已选择6行。

已用时间: 00: 00: 00.47

16:03:55 SQL> select name,sum(decode(trim(km),'语文',cj,0)) 语文,
16:03:58 2 sum(decode(trim(km),'数学',cj,0)) 数学,
16:03:58 3 sum(decode(trim(km),'英语',cj,0)) 英语
16:03:59 4 from test group by name;

NAME 语文 数学 英语
---------- ---------- ---------- ----------
李四 78 85 78
张三 80 86 75

已用时间: 00: 00: 00.15
16:03:59 SQL>
[Q]如何实现行列转换
[A]1、固定列数的行列转换

student subject grade
---------------------------
student1 语文 80
student1 数学 70
student1 英语 60
student2 语文 90
student2 数学 80
student2 英语 100
……
转换为
语文 数学 英语
student1 80 70 60
student2 90 80 100
……
语句如下:
select student,sum(decode(subject,'语文', grade,null)) "语文",
sum(decode(subject,'数学', grade,null)) "数学",
sum(decode(subject,'英语', grade,null)) "英语"
from table
group by student

2、不定列行列转换

c1 c2
--------------
1 我
1 是
1 谁
2 知
2 道
3 不
……
转换为
1 我是谁
2 知道
3 不
这一类型的转换必须借助于PL/SQL来完成,这里给一个例子
CREATE OR REPLACE FUNCTION get_c2(tmp_c1 NUMBER)
RETURN VARCHAR2
IS
Col_c2 VARCHAR2(4000);
BEGIN
FOR cur IN (SELECT c2 FROM t WHERE c1=tmp_c1) LOOP
Col_c2 := Col_c2||cur.c2;
END LOOP;
Col_c2 := rtrim(Col_c2,1);
RETURN Col_c2;
END;
/
SQL> select distinct c1 ,get_c2(c1) cc2 from table;即可

关于oracle中纵向记录横向显示的问题举例说明

最近在论坛里经常看到有朋友问这个问题,下面列举两个真实问答例子来说明 一下:

例一:

问:(贴子地址:http://community.csdn.net/Expert/topic/5722/5722287.xml?temp=9.182376E-02

表如下:
ID NO Name Course Score
1 001 赵 语文 80
2 001 赵 数学 40
3 001 赵 英语 60
4 002 李 语文 50
5 002 李 数学 30
6 003 唐 语文 20
Sql语句执行结果如下:
NO Name AllCouse 总分
001 赵 语文,数学,英语 180
002 李 语文,数学 80
003 唐 语文 20

答:

如果本例中的学科数量是有限的并且是已知的,则可以使用遍历的方法,用一个sql语句来实现:

select no,name,yw||xx||yy AllCouse,"语文"+"数学"+"英语" 总分 from
(select no,name, case when 语文<>0 then '语文' end yw,case when 数学<>0 then ',数学' end xx,case when 英语<>0 then ',英语' end yy,
"语文","数学","英语" from
(select no,name ,nvl(sum("语文"),0) "语文",nvl(sum("数学"),0) "数学",nvl(sum("英语"),0) "英语"
from (select no,name,
case when Course='语文' then nvl(SUM(score),0) end "语文",
case when Course='数学' then nvl(SUM(score),0) end "数学",
case when Course='英语' then nvl(SUM(score),0) end "英语"

from lht_test
group by no,name,course) t
group by no,name) tt) ttt

例二:

问:(贴子地址:http://community.csdn.net/Expert/topic/5762/5762748.xml?temp=7.850283E-02

table1(id varchar2(10), name varchar2(10))

id name
1 aa
1 bb
1 cc
2 xx
3 yy
3 zz
...

想得到一个结果集如下:
id names
1 aa+bb+cc
2 xx
3 yy+zz
...

答:

这种情况中,name的值是不可预知的,则只能通过存储过程来返回一个记录集来实现:

先定义一个记录集的type,
create or replace type t_name as object
(
Id number(10),
Name varchar2(20),
);
create or replace type t_tab_names as table
of t_name;

create or replace procedure p_test (p_tTab_names out t_tab_names) as
i number;
flag number;
vtemp varchar2(100);
tname t_name;
begin
i:=0;
p_tTab_names:=new t_tab_names();
for v in (select id from table1 group by id) loop
i:=i+1;
flag:=0;
for vv in (select id,name from table1 where id=v.id) loop
if (flag=0) then
vtemp:=vv.name;
else
vtemp:=vtemp||'+'||vv.name;
end if;
flag:=1;
end loop;

tname.id:=v.id;
tname.name:=vtemp;
p_tTab_names.extend;
p_tTab_names(i):=tname;
end loop;

exception when others then
dbms_output.put_line(sqlerrm);

end p_test;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: