Oracle WITH语句的用法

本文介绍了Oracle9i新增的WITH语法,可用于命名查询中的子查询并置于SELECT语句之首,提升复杂查询的可读性和性能。通过示例展示了WITH语法如何简化含有聚集和外连接的SQL语句,并说明了WITH定义的子查询在整个查询中的可见性。

Oracle WITH

Oracle9i新增WITH语法,可以将查询中的子查询命名,放到SELECT语句的最前面。

一个简单的例子: 

SQL> WITH
2 SEG AS (SELECT SEGMENT_NAME, SUM(BYTES)/1024 K FROM USER_SEGMENTS GROUP BY SEGMENT_NAME),
3 OBJ AS (SELECT OBJECT_NAME, OBJECT_TYPE FROM USER_OBJECTS)
4 SELECT O.OBJECT_NAME, OBJECT_TYPE, NVL(S.K, 0) SIZE_K
5 FROM OBJ O, SEG S
6 WHERE O.OBJECT_NAME = S.SEGMENT_NAME (+)
7 ;
OBJECT_NAME OBJECT_TYPE SIZE_K
------------------------------ ------------------- ----------
DAIJC_TEST TABLE 128
P_TEST PROCEDURE 0
IND_DAIJC_TEST_C1 INDEX 128

通过WITH语句定义了两个子查询SEG和OBJ,在随后的SELECT语句中可以直接对预定义的子查询进行查询。从上面的例子也可以看出,使用WITH语句,将一个包含聚集、外连接等操作SQL清晰的展现出来。

WITH定义的子查询不仅可以使查询语句更加简单、清晰,而且WITH定义的子查询还具有在SELECT语句的任意层均可见的特点。

即使是在WITH的定义层中,后定义的子查询都可以使用前面已经定义好的子查询: 

SQL> WITH
2 Q1 AS (SELECT 3 + 5 S FROM DUAL),
3 Q2 AS (SELECT 3 * 5 M FROM DUAL),
4 Q3 AS (SELECT S, M, S + M, S * M FROM Q1, Q2)
5 SELECT * FROM Q3;
S M S+M S*M
---------- ---------- ---------- ----------
8 15 23 120

利用WITH定义查询中出现多次的子查询还能带来性能提示。Oracle会对WITH进行性能优化,当需要多次访问WITH定义的子查询时,Oracle会将子查询的结果放到一个临时表中,避免同样的子查询多次执行,从而有效的减少了查询的IO数量。

可惜的是,WITH语句只能用在SELECT语句中,UPDATE和DELETE语句不支持WITH语法: 

SQL> SET AUTOT OFF
SQL> SET TIMING OFF
SQL> WITH SUBQ AS (SELECT 1 FROM DUAL)
2 SELECT ID, NAME FROM T_WITH WHERE ID IN (SELECT * FROM SUBQ);

ID NAME
---------- ------------------------------
1 STANDARD

SQL> WITH SUBQ AS (SELECT 1 FROM DUAL)
2 UPDATE T_WITH SET ID = 1 WHERE ID IN (SELECT * FROM SUBQ);
UPDATE T_WITH SET ID = 1 WHERE ID IN (SELECT * FROM SUBQ)
*第 2 行出现错误:
ORA-00928: 缺失 SELECT 关键字


SQL> WITH SUBQ AS (SELECT 1 FROM DUAL)
2 DELETE T_WITH WHERE ID IN (SELECT * FROM SUBQ);
DELETE T_WITH WHERE ID IN (SELECT * FROM SUBQ)

*第 2 行出现错误:
ORA-00928: 缺失 SELECT 关键字
<think>嗯,用户之前问过关于Oracle中多对多递归查询的问题,现在又问了“with语句使用oracle”。我需要先回想一下之前的回答内容,确保这次回答的一致性和连贯性。之前详细解释了递归WITH子句在多对多关系中的应用,包括语法、示例和注意事项。这次用户可能想更全面地了解WITH语句Oracle中的各种用途,而不仅仅是递归查询。 首先,我需要确认用户的具体需求。他们可能对WITH语句的基础用法、应用场景或高级功能感兴趣。可能用户在使用Oracle时遇到了需要优化查询、重用子查询或者处理复杂逻辑的情况,因此想深入了解WITH语句的使用方法。 接下来,我需要整理WITH语句的不同用途。除了递归查询,OracleWITH子句(即公共表表达式,CTE)主要用于简化复杂查询,提高可读性,避免重复子查询。可能还需要提到它的临时视图特性,以及如何在同一个查询中多次引用同一个CTE。 然后,要考虑用户可能的疑问点。比如,WITH语句和临时表的区别,性能优化方面的考虑,或者如何避免常见的错误,比如循环引用或无限递归。特别是用户之前接触过递归查询,可能需要强调递归CTE和非递归CTE的不同之处,以及如何正确使用它们。 另外,用户可能希望看到具体的示例,特别是实际应用中的案例,比如分步统计、数据去重、层次查询等。这些例子能帮助他们更好地理解如何在实际项目中应用WITH语句。同时,需要确保示例的SQL语法正确,符合Oracle的标准,特别是版本兼容性,比如CYCLE子句在11g及以上版本才支持。 还要注意用户可能存在的误区。例如,WITH子句虽然可以提升可读性,但过度使用或不当使用可能导致性能问题。需要提醒用户合理使用,并结合索引、执行计划等优化手段。 最后,总结部分要简明扼要,强调WITH语句的优势和适用场景,帮助用户快速抓住重点。同时,可以推荐一些进一步学习的资源或最佳实践,方便用户深入探索。</think>以下是对Oracle中`WITH`语句(公共表表达式,CTE)的详细介绍,分步骤说明其使用方法和场景: --- ### 一、`WITH`语句基础 #### 1. **定义** - `WITH`语句(Common Table Expression,CTE)用于定义**临时命名查询结果集**,可在同一查询中多次引用。 - 类似“临时视图”,但仅存在于当前查询的生命周期内。 #### 2. **核心优势** - **简化复杂查询**:将多层嵌套的子查询拆分为逻辑块。 - **代码重用**:避免重复编写相同子查询。 - **递归支持**:处理树形/图结构数据(需配合`UNION ALL`)。 --- ### 二、基本语法 ```sql WITH cte_name1 (列1, 列2, ...) AS ( SELECT ... FROM ... -- 子查询1 ), cte_name2 AS ( SELECT ... FROM cte_name1 -- 子查询2(可引用其他CTE) ) SELECT * FROM cte_name2; -- 最终查询 ``` --- ### 三、典型应用场景 #### 1. **简化复杂查询** **示例**:统计部门平均工资及高于平均工资的员工 ```sql WITH dept_avg AS ( SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id ) SELECT e.employee_id, e.salary, d.avg_sal FROM employees e JOIN dept_avg d ON e.department_id = d.department_id WHERE e.salary > d.avg_sal; ``` #### 2. **分步计算** **示例**:分阶段统计销售额 ```sql WITH region_sales AS ( SELECT region, SUM(amount) total FROM orders GROUP BY region ), top_regions AS ( SELECT region FROM region_sales WHERE total > 1000000 ) SELECT * FROM top_regions; ``` #### 3. **递归查询** **示例**:查询员工层级关系(树形结构) ```sql WITH employee_tree (employee_id, name, manager_id, level) AS ( -- 锚点:顶级管理者(无上级) SELECT employee_id, name, manager_id, 1 FROM employees WHERE manager_id IS NULL UNION ALL -- 递归:逐层向下查找下属 SELECT e.employee_id, e.name, e.manager_id, et.level + 1 FROM employees e JOIN employee_tree et ON e.manager_id = et.employee_id ) SELECT * FROM employee_tree; ``` --- ### 四、高级用法 #### 1. **多CTE串联** ```sql WITH temp1 AS (SELECT ...), temp2 AS (SELECT ... FROM temp1), temp3 AS (SELECT ... FROM temp2) SELECT * FROM temp3; ``` #### 2. **递归中的循环检测**(Oracle 11g+) ```sql WITH employee_tree (...) AS (...) CYCLE employee_id SET is_cycle TO 'Y' DEFAULT 'N' SELECT * FROM employee_tree WHERE is_cycle = 'N'; ``` #### 3. **MATERIALIZE提示强制物化**(性能优化) ```sql WITH /*+ MATERIALIZE */ temp AS (SELECT ...) SELECT * FROM temp; ``` --- ### 五、性能注意事项 1. **避免过度嵌套**:超过3层的CTE可能影响可读性。 2. **索引优化**:确保CTE中的JOIN字段已建索引。 3. **递归深度控制**:使用`WHERE level < N`限制层级。 4. **替代方案**:复杂场景可考虑临时表或内联视图。 --- ### 六、与子查询的对比 | 特性 | `WITH`语句 | 子查询 | |---------------------|---------------------|-------------------| | 可读性 | 高(分块命名) | 低(嵌套复杂) | | 重用性 | 可多次引用 | 不可重用 | | 递归支持 | 支持 | 不支持 | | 执行计划优化 | 可能被优化器物化 | 通常内联执行 | --- ### 七、实际案例 #### 场景:统计部门及子部门的总人数 ```sql WITH dept_hierarchy (department_id, parent_id, level) AS ( SELECT department_id, parent_id, 1 FROM departments WHERE parent_id IS NULL -- 根部门 UNION ALL SELECT d.department_id, d.parent_id, dh.level + 1 FROM departments d JOIN dept_hierarchy dh ON d.parent_id = dh.department_id ) SELECT dh.department_id, COUNT(e.employee_id) AS total_employees FROM dept_hierarchy dh LEFT JOIN employees e ON dh.department_id = e.department_id GROUP BY dh.department_id; ``` --- ### 总结 Oracle的`WITH`语句通过模块化查询逻辑显著提升代码可维护性,尤其适用于: 1. 递归数据处理(如组织结构、BOM表) 2. 多步骤复杂计算 3. 需要重复引用的子查询场景 建议在涉及多层嵌套或递归时优先使用`WITH`语句,并结合执行计划分析优化性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值