当前位置: 首页 > ops >正文

[Oracle数据库] Oracle 复杂查询

对于刚接触 Oracle 数据库的初学者来说,简单查询(如SELECT * FROM 表名)可能不难掌握,但面对复杂业务场景时,就需要更强大的查询能力。本文将围绕 Oracle 复杂查询的核心知识点展开,包括条件逻辑、分组函数、分组查询、子查询、分页及合并查询,用通俗的语言和实例帮你快速入门。

一、条件逻辑:让查询学会 “判断”

在 SQL 中,我们经常需要根据不同条件返回不同结果,这就需要用到条件逻辑。Oracle 中最常用的条件逻辑工具是CASE...WHEN语句,它类似其他编程语言中的if-else结构。

1️⃣逻辑判断 vs 条件判断

  • 逻辑判断:用ANDORNOT等逻辑运算符对条件表达式进行计算,最终返回truefalse(例如:sal > 1000 AND deptno = 20)。
  • 条件判断:根据条件决定执行哪个分支的操作(例如:“如果工资低于 1500,返回‘低’;否则返回‘高’”)。

2️⃣CASE...WHEN:两种实用形式

CASE...WHEN有两种形式,分别适用于不同场景:

(1)简单 CASE 表达式:匹配固定值

当需要将一个表达式的值与多个固定值对比时,用简单 CASE。

语法:

sql

CASE 表达式WHEN 值1 THEN 结果1WHEN 值2 THEN 结果2...ELSE 默认结果
END

实例:根据员工职位返回不同问候语

sql

SELECT EMPNO, ENAME, CASE job WHEN 'PRESIDENT' THEN '总裁辛苦了' WHEN 'MANAGER' THEN '经理好' WHEN 'ANALYST' THEN '组长干的不错' WHEN 'SALESMAN' THEN '跑业务去' WHEN 'CLERK' THEN '嗯' END 问候语 
FROM emp;
(2)搜索 CASE 表达式:处理复杂条件

当条件是范围、多字段组合等复杂逻辑时,用搜索 CASE。

语法:

sql

CASEWHEN 条件1 THEN 结果1WHEN 条件2 THEN 结果2...ELSE 默认结果
END

实例:根据工资范围划分等级

sql

SELECT EMPNO, ENAME, CASE WHEN sal < 1500 THEN 'Low' WHEN sal BETWEEN 1500 AND 2000 THEN 'Medium' WHEN sal > 2000 THEN 'High' ELSE 'Unknown' END AS salary_grade 
FROM emp;

二、分组函数:对数据 “汇总计算”

分组函数(又称聚合函数)用于对一组数据进行计算并返回单个结果,常与分组查询配合使用。核心注意点:分组函数不能直接与非分组字段同时出现在SELECT中(除非非分组字段在GROUP BY中)。

常用分组函数及实例

函数作用实例(基于 emp 表)
COUNT统计非空值的数量SELECT COUNT(sal) FROM emp;(统计有工资的员工数)
MIN求列的最小值SELECT MIN(sal) FROM emp;(查询最低工资)
MAX求列的最大值SELECT MAX(sal) FROM emp;(查询最高工资)
AVG求列的平均值(忽略 NULL)SELECT AVG(sal) FROM emp;(查询平均工资)

小提示:如果要包含 NULL 值计算(例如工资为 NULL 时按 0 处理),可结合NVL函数:AVG(NVL(sal, 0))

三、分组查询:按规则 “拆分数据”

当需要按某一列(如部门、职位)拆分数据并分别计算时,需用GROUP BY子句。

1️⃣GROUP BY 基础用法

语法:

sql

SELECT 分组字段, 分组函数
FROM 表名
GROUP BY 分组字段;

实例:

  • 按部门编号统计员工人数:

    sql

    SELECT deptno, COUNT(*) AS "人数" FROM emp GROUP BY deptno;
    
  • 按部门和职位统计人数(多字段分组):

    sql

    SELECT deptno, job, COUNT(*) FROM emp GROUP BY deptno, job ORDER BY deptno;
    

注意:GROUP BY后的字段可不包含在SELECT中(但通常会包含以便区分分组)。

2️⃣HAVING:对分组结果 “二次过滤”

HAVING子句用于过滤分组后的结果,与WHERE的区别如下:

特性WHEREHAVING
执行时机分组前过滤数据分组后过滤分组结果
能否用聚合函数不能

实例:

  • 查询员工人数大于 5 的部门:

    sql

    SELECT deptno, COUNT(*) FROM emp GROUP BY deptno HAVING COUNT(*) > 5;
    
  • 查询 20 号部门的最低工资(分组后过滤):

    sql

    SELECT MIN(sal) FROM emp GROUP BY deptno HAVING deptno = 20;
    

四、子查询:让查询 “嵌套起来”

当一次查询无法完成需求时(例如 “先查 A 的部门,再查该部门所有员工”),可以用子查询(嵌套在其他 SQL 中的SELECT语句)。

子查询的基本规则

  • 必须用括号()包裹;
  • 可嵌套多层;
  • 根据返回结果行数,分为单行、多行、多列子查询。

1️⃣单行子查询:返回 1 行结果

=><等运算符连接,适用于子查询结果唯一的场景。

实例:查询 SMITH 所在部门的所有员工

sql

SELECT ename, sal, deptno 
FROM emp 
WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SMITH');

2️⃣多行子查询:返回多行结果

需用INALLANY等运算符:

  • IN:匹配子查询结果中的任意一个值;
  • ALL:匹配子查询结果中的所有值;
  • ANY:匹配子查询结果中的任意一个值(与IN类似,但ANY可结合比较运算符)。

实例:

  • IN查询与 10 号部门工种相同的员工:

    sql

    SELECT ename, job, sal, deptno 
    FROM emp 
    WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10);
    
  • ALL查询工资高于 30 号部门所有人的员工:

    sql

    SELECT ename, sal, deptno 
    FROM emp 
    WHERE sal > ALL (SELECT sal FROM emp WHERE deptno = 30);
    

    (等价于sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30),效率更高)

3️⃣多列子查询:返回多列结果

当条件涉及多个字段时,用多列子查询。

实例:查询与 SMITH 同部门且同工种的员工

sql

SELECT ename, job, sal, deptno 
FROM emp 
WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = 'SMITH');

4️⃣子查询的常见应用场景

  • 在 FROM 中使用:作为虚拟表(需指定别名),例如查询各部门中工资高于部门平均的员工:

    sql

    SELECT emp.deptno, ename, sal, dept.avgsal 
    FROM emp, (SELECT deptno, AVG(sal) AS avgsal FROM emp GROUP BY deptno) dept 
    WHERE emp.deptno = dept.deptno AND sal > dept.avgsal;
    
  • 在 DML 中使用:

    • 插入数据:INSERT INTO 表名 SELECT ...
    • 更新数据:UPDATE 表名 SET ... = (子查询)
    • 删除数据:DELETE FROM 表名 WHERE ... = (子查询)
  • 在 DDL 中使用:复制表结构和数据(加WHERE 1=2只复制结构):

    sql

    CREATE TABLE new_emp(id, name, sal, job, deptno) 
    AS SELECT empno, ename, sal, job, deptno FROM emp;
    

五、分页查询:批量数据 “分段显示”

Oracle 中通过伪列实现分页,常用的伪列有rownum(逻辑编号,从 1 开始)和rowid(物理编号)。其中rownum最常用。

rownum 分页的关键步骤

rownum的特性:总是从 1 开始编号,若结果集中没有rownum=1,则后续编号也不存在(因此不能直接用rownum >=6 AND rownum <=9)。

查询第 6-9 条记录的步骤:

  • 先获取前 10 条记录并编号:

    sql

    SELECT e.*, rownum rn FROM (SELECT * FROM emp) e WHERE rownum <= 10;
    
  • 嵌套查询,筛选编号大于 6 的记录:

    sql

    SELECT * FROM (SELECT e.*, rownum rn FROM (SELECT * FROM emp) e WHERE rownum <= 10
    ) WHERE rn > 6;
    

六、合并查询:多结果集 “组合运算”

UNIONUNION ALLINTERSECTMINUS组合多个查询结果,适用于大数据量场景。

操作符作用示例(查询工资 > 2500 或职位为 MANAGER 的员工)
UNION并集(去重)SELECT ... WHERE sal>2500 UNION SELECT ... WHERE job='MANAGER'
UNION ALL并集(不去重,效率更高)SELECT ... UNION ALL SELECT ...
INTERSECT交集(同时存在于两个结果集)SELECT ... INTERSECT SELECT ...
MINUS差集(存在于第一个集但不在第二个)SELECT ... MINUS SELECT ...

注意:组合的查询结果需列数相同、类型兼容;LOB、LONG 等特殊类型不支持部分操作符。

总结

Oracle 复杂查询是数据库操作的核心技能,本文涵盖了条件逻辑(CASE...WHEN)、分组函数、分组查询(GROUP BY+HAVING)、子查询、分页及合并查询等重点。初学者需注意:

  • 分组函数与GROUP BY的配合使用;
  • WHEREHAVING的区别;
  • 子查询的嵌套逻辑和rownum分页的特性。
http://www.xdnf.cn/news/17915.html

相关文章:

  • 当 GitHub 宕机时,我们如何协作?
  • Flink Sql 按分钟或日期统计数据量
  • 从 “视频孪生” 到 “视频动态目标三维重构”:技术演进与核心突破
  • PHP域名授权系统网站源码_授权管理工单系统_精美UI_附教程
  • 基于W55MH32Q-EVB 实现 HTTP 服务器配置 OLED 滚动显示信息
  • 企业级Java项目金融应用领域——银行系统
  • 【P40 6-3】OpenCV Python——图像融合(两张相同属性的图片按比例叠加),addWeighted()
  • B3924 [GESP202312 二级] 小杨的H字矩阵
  • Java后台生成多个Excel并用Zip打包下载
  • 《Python学习之字典(一):基础操作与核心用法》
  • 基于 EC 数据与大模型技术实现天气预报:从数据到上线的全栈方法
  • 学习嵌入式第三十天
  • C++进阶:IO流
  • 【Vibe Coding 工程之 StockAnalyzerPro 记录】- EP3.Phase 2股票列表管理功能
  • JCTools 无锁并发队列基础:ConcurrentCircularArrayQueue
  • TDengine IDMP 高级功能(4. 元素引用)
  • C# 反射和特性(关于应用特性的更多内容)
  • 解锁JavaScript性能优化:从理论到实战
  • C#WPF实战出真汁09--【消费开单】--选择菜品
  • 一次性能排查引发的Spring MVC深度思考
  • Element Plus 中 el-input 限制为数值输入的方法
  • Docker自定义镜像
  • 自动驾驶中的传感器技术24.1——Camera(16)
  • 算法训练营day53 图论④ 110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长
  • Conda创建py3.10环境(股票),并且安装程序包的命令
  • 元宇宙教育:打破时空限制的学习革命
  • 汽车大灯ABD算法介绍
  • SpringAI中的模块化链式Advisor调用(源码学习)
  • B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • Linux 多线程:线程回收策略 线程间通信(互斥锁详解)