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

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

建立表结构,在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()函数里面的语句来控制。

<think>好的,我现在需要帮助用户解决SQL中如何根据同一字段的不值进行查询的问题。首先,用户可能指的是根据同一字段的多个值来筛选记录,比如查询某个字段等于多个值中的一个的情况。这时候,我应该想到使用IN关键字,例如SELECT * FROM table WHERE column IN (value1, value2)。不过用户的问题可能还有其他情况,比如需要时满足多个不值,这时候可能需要自连接或者子查询。 接下来,用户可能想了解如何统计同一字段值的数量,这时候可以用GROUP BY和COUNT,比如SELECT column, COUNT(*) FROM table GROUP BY column。另外,CASE语句也是一个有用的工具,可以在SELECT子句中处理不的值,例如分类或计算。 还有可能用户需要的是在同一字段中根据不的条件返回不结果,比如使用CASE WHEN THEN结构。或者,他们可能需要将同一字段的不值作为不的列来展示,这时可能需要使用PIVOT或者条件聚合。 我需要考虑用户可能的场景,比如数据分析、报表生成,或者是简单的数据筛选。比如,用户可能有一个订单表,想找出所有状态为“待发货”或“已发货”的订单,这时候用IN。或者,他们可能需要统计每个地区的销售数量,这时用GROUP BY。 也有可能用户的问题更复杂,比如同一字段的不值需要满足多个条件,例如查找时有订单状态为“完成”和“取消”的客户,这时候可能需要自连接或者使用HAVING子句结合聚合函数。 我需要确保覆盖不的可能性,并提供相应的示例,时保持解释清晰易懂。应该分情况讨论,比如单一字段多值匹配、聚合统计不值、条件处理以及行列等场景,每个情况给出对应的SQL语句示例,并简单说明其用途。 最后,要检查是否有遗漏的情况,确保回答全面,帮助用户理解不的方法及其应用场景。</think>在 SQL 中,根据同一字段的不值进行查询或处理有多种常见场景,以下是几种典型用法及示例: --- ### **1. 筛选同一字段的多个值(逻辑OR)** 若需要查询字段包含多个特定值的记录,可用 **`IN` 关键字**或 **`OR` 条件**: ```sql -- 使用 IN (推荐简洁写法) SELECT * FROM 表名 WHERE 字段名 IN ('值1', '值2', '值3'); -- 等价于 OR 条件 SELECT * FROM 表名 WHERE 字段名 = '值1' OR 字段名 = '值2' OR 字段名 = '值3'; ``` --- ### **2. 统计不值的数量(分组聚合)** 若需统计某字段值的出现次数,使用 **`GROUP BY` + `COUNT`**: ```sql SELECT 字段名, COUNT(*) AS 数量 FROM 表名 GROUP BY 字段名; ``` **输出示例**: ``` 字段名 | 数量 --------|----- 值1 | 5 值2 | 3 值3 | 8 ``` --- ### **3. 时满足多个不值(逻辑AND)** 若需查找 **同一字段时满足多个不值** 的记录(需结合自连接或子查询): ```sql -- 示例:查找时购买过“商品A”和“商品B”的用户 SELECT user_id FROM 订单表 WHERE 商品名 = '商品A' INTERSECT -- 或使用 JOIN 实现 SELECT user_id FROM 订单表 WHERE 商品名 = '商品B'; ``` --- ### **4. 条件分支处理不值(分类计算)** 使用 **`CASE WHEN`** 根据字段值返回不结果: ```sql SELECT CASE WHEN 字段名 = '值1' THEN '分类A' WHEN 字段名 = '值2' THEN '分类B' ELSE '其他' END AS 分类, COUNT(*) AS 数量 FROM 表名 GROUP BY 分类; ``` --- ### **5. 将不为列(行列/PIVOT)** 使用 **`CASE` + 聚合函数** 或数据库的 **`PIVOT`** 功能(如 SQL Server): ```sql -- 示例:统计不城市的销售额(每个城市作为一列) SELECT SUM(CASE WHEN 城市 = '北京' THEN 销售额 ELSE 0 END) AS 北京销售额, SUM(CASE WHEN 城市 = '上海' THEN 销售额 ELSE 0 END) AS 上海销售额 FROM 销售表; ``` --- ### **6. 排除特定值** 若需排除某字段的某些值,使用 **`NOT IN`**: ```sql SELECT * FROM 表名 WHERE 字段名 NOT IN ('不需要的值1', '不需要的值2'); ``` --- ### **示例数据演示** 假设有 `students` 表: | id | name | gender | score | |----|------|--------|-------| | 1 | 张三 | 男 | 85 | | 2 | 李四 | 女 | 92 | | 3 | 王五 | 男 | 78 | **场景1**:查询所有男生或分数≥90的学生 ```sql SELECT * FROM students WHERE gender = '男' OR score >= 90; ``` **场景2**:统计男女平均分 ```sql SELECT gender, AVG(score) AS 平均分 FROM students GROUP BY gender; ``` --- 根据具体需求选择合适的方法即可。如果有更具体的场景描述,可以提供进一步优化写法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值