[转]将查询结果中同一字段多行合并到一行上的SQL语句写法

本文介绍了在Oracle数据库中实现字段值连接的一种方法,利用SYS_CONNECT_BY_PATH函数结合其他SQL技巧,实现了将同一部门的不同员工姓名及其它信息连接显示在同一行的需求。

在开发过程中经常碰到要实现按照某一字段,将其它字段中不同的值连接后显示到一行上的需求。本人总结了以下几种方法,在实际开发中可以参考。

建立表结构,在Oracle9i上。
CREATE TABLE temp
(
DEPTNO   int,
ENAME   varchar(20 BYTE),
SEX   varchar(20 BYTE),
AGE   varchar(20 BYTE)
);

insert into temp values(10,'aaa','F','18');
insert into temp values(10,'bbb','F','19');
insert into temp values(10,'ccc','F','20');
insert into temp values(20,'ddd','M','21');
insert into temp values(20,'eee','M','22');
insert into temp values(20,'fff','M','23');
insert into temp values(30,'hhh','X','24');
insert into temp values(30,'ggg','X','25');
insert into temp values(30,'yyy','X','26');
insert into temp values(30,'ttt','X','27');

commit;

第一种写法:

SELECT DISTINCT FIRST_VALUE (deptno) OVER (PARTITION BY deptno ORDER BY lv DESC) AS deptno,
                FIRST_VALUE (ename) OVER (PARTITION BY deptno ORDER BY lv DESC) AS ename
           FROM (SELECT deptno, SYS_CONNECT_BY_PATH (ename, ' ') ename,
                            LEVEL lv FROM (SELECT deptno, ename,
                                    LAG (ename, 1, NULL) OVER (PARTITION BY deptno ORDER BY ename) ename_1
                               FROM (SELECT deptno, ename FROM temp))
                 CONNECT BY PRIOR ename = ename_1
                   ORDER BY deptno)

结果如下:

10| aaa bbb ccc
20| ddd eee fff
30| ggg hhh ttt yyy

改进后可以增加一列如下:

SELECT DISTINCT FIRST_VALUE (deptno) OVER (PARTITION BY deptno ORDER BY lv DESC) AS deptno,
                FIRST_VALUE (sex) OVER (PARTITION BY sex ORDER BY lv DESC) AS sex,
                FIRST_VALUE (ename) OVER (PARTITION BY deptno ORDER BY lv DESC) AS ename
           FROM (SELECT deptno, sex, SYS_CONNECT_BY_PATH (ename, ' ') ename, LEVEL lv
                       FROM (SELECT deptno, ename, sex,
                                    LAG (ename, 1, NULL) OVER (PARTITION BY deptno ORDER BY ename) ename_1
                               FROM (SELECT deptno, ename, sex FROM temp))
                 CONNECT BY PRIOR ename = ename_1
                   ORDER BY deptno)

结果如下:
10|F| aaa bbb ccc
20|M| ddd eee fff
30|X| ggg hhh ttt yyy

第二种写法:

SELECT deptno, SYS_CONNECT_BY_PATH (ename, ' ') AS ename, sex,
           SYS_CONNECT_BY_PATH (age, ' ') AS age
      FROM (SELECT deptno, ename, sex, age, RANK () OVER (ORDER BY deptno)
                   + ROW_NUMBER () OVER (ORDER BY deptno) rn,
                   ROW_NUMBER () OVER (PARTITION BY deptno ORDER BY deptno) rm
              FROM temp) a1
     WHERE a1.ROWID IN (SELECT MAX (a2.ROWID) FROM temp a2 WHERE a2.deptno = a1.deptno)
START WITH rm = 1
CONNECT BY PRIOR rn = rn - 1

结果如下:
10| aaa bbb ccc|F| 18 19 20
20| ddd eee fff|M| 21 22 23
30| hhh ggg yyy ttt|X| 24 25 26 27

 

出自:http://hi.baidu.com/rel_conquer/blog/item/fb3bb6f3a7a5185d352acc08.html

 

 

 

Oracle中SYS_CONNECT_BY_PATH函数是非常重要的函数,下面就为您介绍一个使用SYS_CONNECT_BY_PATH函数的例子,实例如下:

  1. create table test (a varchar2(10),b varchar2(10));  
  2.  
  3. INSERT INTO TEST (A, B) VALUES ('1', '我');  
  4. INSERT INTO TEST (A, B) VALUES ('1', '们');  
  5. INSERT INTO TEST (A, B) VALUES ('2', '一');  
  6. INSERT INTO TEST (A, B) VALUES ('2', '起');  
  7. COMMIT;  
  8.  
  9. SELECT A, B FROM TEST  
  10.  
  11. A          B  
  12. ---------- ----------  
  13. 1          我  
  14. 1          们  
  15. 2          一  
  16. 2          起  
  17.  
  18. 现在需要达到如下的效果,  
  19. A          B  
  20. ---------- ----------  
  21. 1          我,们  
  22. 2          一,起  
  23.  

只想用一句sql来返回结果。

  1. SELECT A, LTRIM(MAX(SYS_CONNECT_BY_PATH(B, ',')), ',') B  
  2. FROM (SELECT B, A, ROW_NUMBER() OVER(PARTITION BY A ORDER BY B DESC) RN  
  3.           FROM TEST)  
  4. START WITH  RN  =  1  
  5. CONNECT BY RN -  1  =  PRIOR  RN  
  6.        AND  A  =  PRIOR  A  
  7. GROUP BY A; 

其中,SYS_CONNECT_BY_PATH函数主要作用是可以把一个父节点下的所有子节点通过某个字符进行区分,然后连接在一个列中显示。

row_number函数的用途是非常广泛,这个函数的功能是为查询出来的每一行记录生成一个序号。生产序号的方法通过over()函数里面的语句来控制。

在 MySQL 查询语句使用 GROUP BY 时取时间字段最大值有以下几种常见写法: ### 方法一:使用 MAX() 函数 下面的示例查询从 `reader_market_sharearnings` 表(别名 T1)和 `reader_app_user` 表(别名 T2)中,选取满足 `T1.doc_id` 为指定值的数据,按 `T1.profit_user_id` 分组,统计每组中 `T1.shared_user_id` 的数量,时获取每组中 `T1.insert_dt` 的最大值。 ```sql SELECT T2.nick_name as nickName, count(T1.shared_user_id) AS shareNum, max(T1.insert_dt) as insertDt FROM reader_market_sharearnings T1 LEFT JOIN reader_app_user T2 ON T1.profit_user_id = T2.id WHERE T1.doc_id = 'specilf8d628b729984c608bfdc1d6500abbb2' GROUP BY T1.profit_user_id ORDER BY shareNum DESC ``` 该语句使用 `MAX()` 函数直接获取时间字段的最大值,适用于在分组后仅需要获取时间字段最大值以及其他聚合结果的场景 [^1]。 ### 方法二:子查询结合 GROUP BY 以下示例从 `posts` 表中获取按 `tid` 分组,每组中 `dateline` 最大的记录。需要注意的是,原引用中的语句存在语法错误,正确的写法应该添加括号和空格,以下是修正后的示例: ```sql SELECT * FROM ( SELECT * FROM posts ORDER BY dateline DESC ) AS BIAOMING GROUP BY tid ORDER BY dateline DESC LIMIT 10 ``` 此方法先对表按时间字段降序排序,再进行分组操作,能够获取到每组中时间字段最大的整条记录,适用于需要获取完整记录的场景 [^2][^3]。 ### 方法三:子查询结合 LIMIT 下面的示例从 `tp_exam_user_number` 表中获取按 `user_id` 分组,每组中 `true_num` 最大的记录。 ```sql SELECT * FROM ( SELECT * FROM tp_exam_user_number a ORDER BY true_num DESC LIMIT 100000 ) AS aa GROUP BY user_id ``` 该方法样是先对表进行排序,再分组,使用 `LIMIT` 限制子查询结果集大小,适用于数据量较大时,先缩小数据范围再进行分组操作的场景 [^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值