Oracle with语句的用法

本文详细介绍了 Oracle 数据库中 WITH 语句的用法及其优势。WITH 语句能够提高 SQL 查询的可读性和执行效率,通过创建公共临时表减少重复计算。文章还提供了多个示例说明如何在复杂查询中有效利用 WITH 语句。

Oracle with语句的用法

 

Oracle数据库中,使用with语句可以实现子查询,提高语句执行的效率,下文对with语句的用法作了详细的介绍,供您参考学习。

 

Oracle with语句是经常可以见到的语句,下面就为您详细介绍Oracle with语句的用法,如果您对Oracle with语句感兴趣的话,不妨一看。

当查询中多次用到某一部分时,可以用Oracle with语句创建一个公共临时表。因为子查询在内存临时表中,避免了重复解析,所以执行效率会提高不少。临时表在一次查询结束自动清除。

一般语法格式:

 
  1. with   
  2. alias_name1 as    (subquery1),  
  3. alias_name2 as    (subQuery2),  
  4. ……  
  5. alias_nameN as    (subQueryN)  
  6. select col1,col2…… col3   
  7.      from alias_name1,alias_name2……,alias_nameN 

Oracle with语句的例子:

 
  1. 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; 

输出结果:

 
  1. S M S+M S*M  
  2. ---------- ---------- ---------- ----------  
  3. 8 15 23 120  
  4.  

【编辑推荐】

常见的ORACLE数据类型介绍

查询Oracle日志文件的方法

Oracle并行查询方式的利用

Oracle索引的优化设计

16种oracle查询日期语句

=======================================

 

Oracle With Clause

        本文参考网址:http://psoug.org/reference/with.html

                            http://www.oracle-base.com/articles/misc/with-clause.php

                           http://gennick.com/with.html ------Understanding the WITH Claus

 

        参考文档下载地址:http://ishare.iask.sina.com.cn/f/21674385.html

     The WITH query_name clause lets you assign a name to a subquery block. You can then reference the subquery block multiple places in the query by specifying the query name. Oracle optimizes the query by treating the query name as either an inline view or as a temporary table.
(WITH语句只能位于一条语句的最顶级)
You can specify this clause in any top-level SELECT statement and in most types of subqueries. The query name is visible to the main query and to all subsequent subqueries except the subquery that defines the query name itself.

A WITH clause is really best used when the result of the WITH query is required more than one time in the body of the query such as where one averaged value needs to be compared against two or three times.

Restrictions on Subquery Factoring:

  • You cannot nest this clause. That is, you cannot specify the subquery_factoring_clause within the subquery of another subquery_factoring_clause. However, a query_name defined in one subquery_factoring_clause can be used in the subquery of any subsequent subquery_factoring_clause.(WITH语句不允许嵌套,之前定义的WITH语句可以在它后面的任何一个WITH语句中使用)
  • In a query with set operators, the set operator subquery cannot contain the subquery_factoring_clause, but the FROM subquery can contain the subquery_factoring_clause 

With语句的语法(AS后面的括号是不可以空缺的)

1 WITH <alias_name> AS (subquery_sql_statement)
2 SELECT <column_name_list> FROM <alias>;

简单的with语句:

WITH A AS
 (SELECT * FROM DUAL)
SELECT * FROM A

注意,定义了WITH语句必须在后边的查询中使用,否则提示错误信息:

1 WITH A AS
2  (SELECT * FROM DUAL)
3 SELECT * FROM dual

(错误的原因是因为没有使用定义的WITH语句进行查询)

 

两个with语句的语法:

复制代码

1 WITH <alias_one> AS 
2   (subquery_sql_statement),
3      <alias_two> AS
4   (sql_statement_from_alias_one)
5 SELECT <column_name_list>
6 FROM <alias_one>, <alias_two>
7 WHERE <join_condition>;

复制代码

测试例子:

1 WITH A AS
2  (SELECT * FROM DUAL),
3 B AS
4  (SELECT * FROM DUAL)
5 SELECT * FROM B, A

当在FROM关键子后面没有全部使用定义的WITH语句,他就会提示同上的错误信息:

(不可引用在with子句中定于的查询)

 

在视图中使用WITH语句进行连接:

1 CREATE OR REPLACE VIEW WITH_V AS
2   WITH DEPT_V AS (SELECT * FROM DEPT),
3    EMP_V AS (SELECT * FROM EMP)
4    SELECT D.DNAME,D.LOC,E.* FROM EMP_V E
5    LEFT JOIN DEPT_V D
6    ON D.DEPTNO = E.DEPTNO

     使用WITH AS 语句可以为一个子查询语句块定义一个名称,使用这个子查询名称可以  在查询语句的很多地方引用这个子查询。Oracle 数据库像对待内联视图或临时表一样对待 被引用的子查询名称,从而起到一定的优化作用。with子句是9i新增语法。你可以在任何一个顶层的SELECT 语句以及几乎所有类型的子查询语句前,使用子查询定义子句。被定义的子查询名称可以在主查询语句以及所有的子查询语句中引用,但未定义前不能引用。with子句中不能嵌套定义<也就是with子句中不能有with子句>,但子查询中出现的“子查询定义”语句可以引用已定义的子查询名称。<可以引用前面已经定义的with子句>

WITH子句相关总结:
 

1、在同级select前有多个查询定义的时候,第1个用with,后面的不用with,并且用逗号隔开。

 

2、最后一个with 子句与下面的查询之间不能有逗号,只通过右括号分割,with 子句的查询必须用括号括起来

3、如果定义了with子句,而在查询中不使用,那么会报ora-32035 错误:未引用在with子句中定义的查询名。(至少一个with查询的name未被引用,解决方法是移除未被引用的with查询),注意:只要后面有引用的就可以,不一定非要在主查询中引用,比如后面的with查询也引用了,也是可以的。

 

4、前面的with子句定义的查询在后面的with子句中可以使用。但是一个with子句内部不能嵌套with子句。

 

5、with查询的结果列有别名,引用的时候必须使用别名或*。

 

WITH语句的优点:

(1). SQL可读性增强。比如对于特定with子查询取个有意义的名字等。

(2)、with子查询只执行一次,将结果存储在用户临时表空间中,可以引用多次,增强性能。

     举例:在进行导入EXCEL的过程中,有时候,需要将数据存储在临时表中,当下一次在进行导入的时候,进行清除临时表的数据,但是这时候,有时候发生并发问题的话,两个用户可能会分别操作对方的数据,所以,可能造成混乱,但是可以使用WITH函数和UNION语句拼接一个SQL语句,存储在SESSION中,当需要导出错误信息的时候,可以使用该语句构造数据。

---------------------------WITH语句的使用例子:

1、查询出部门的总薪水大于所有部门平均总薪水的部门。部门表s_dept,员工表s_emp。分析:做这个查询,首先必须计算出所有部门的总薪水,然后计算出总薪水的平均薪水,再筛选出部门的总薪水大于所有部门总薪水平均薪水的部门。那么第1 步with 查询查出所有部门的总薪水,第2 步用with 从第1 步获得的结果表中查询出平均薪水,最后利用这两次 的with 查询比较总薪水大于平均薪水的结果,如下:

复制代码

 1 WITH DEPT_COSTS AS --查询出部门的总工资
 2  (SELECT D.DNAME, SUM(E.SAL) DEPT_TOTAL
 3     FROM DEPT D, EMP E
 4    WHERE E.DEPTNO = D.DEPTNO
 5    GROUP BY D.DNAME),
 6 AVE_COST AS   --查询出部门的平均工资,在后一个WITH语句中可以引用前一个定义的WITH语句
 7  (SELECT SUM(DEPT_TOTAL) / COUNT(*) AVG_SUM FROM DEPT_COSTS)
 8 SELECT *
 9   FROM DEPT_COSTS DC
10  WHERE DC.DEPT_TOTAL > (SELECT AC.AVG_SUM FROM AVE_COST AC)--进行比较

复制代码

2、可以使用前面的数据,在后面的with语句中直接引用。需求,展示根据查询结果查询出的数据,并把根据查询出的结果进行统计,如最大工资,最小工资,平均工资,

进行级联,由于查询的统计数据的条数为1条,所以不会发生笛卡儿积的错误,
1 WITH TEMP_DATA AS --查询基础数据
2  (SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO FROM EMP),
3 TEM_SUM AS --查询统计数据
4  (SELECT MAX(SAL), MIN(SAL), SUM(SAL) FROM TEMP_DATA)
5 SELECT *
6   FROM TEM_SUM, TEMP_DATA --进行级联,由于查询的统计数据的条数为1条,所以不会发生笛卡儿积的错误

 

 

 

3、 with子查询不可嵌套定义,但是后面的with定义可以引用前面的结果集。

1 WITH SELECT_TRADE AS
2  (SELECT TRADE_ID FROM PRODUCT WHERE ID = 1),
3 --后面的with子查询可以引用前面的结果
4 SELECT_TRADEMARK AS
5  (SELECT NAME FROM TRADEMARK WHERE ID = (SELECT TRADE_ID FROM SELECT_TRADE))
6 SELECT * FROM SELECT_TRADEMARK;

 下面的语句错误:因为不允许嵌套定义with语句

复制代码

1 --这条语句错误
2 WITH SELECT_TRADE AS
3 --with中有嵌套with,不允许
4  (WITH TEMP AS
5      (SELECT TRADE_ID FROM PRODUCT WHERE ID = 1)
6     SELECT TRADE_ID FROM TEMP),
7 SELECT_TRADEMARK AS
8  (SELECT NAME FROM TRADEMARK WHERE ID = (SELECT TRADE_ID FROM SELECT_TRADE))
9 SELECT * FROM SELECT_TRADEMARK;

复制代码

 

4、一个复杂的WITH语句例子:在子查询中使用WITH,

复制代码

 1 SELECT A, B
 2   FROM (
 3        --第1个定义t_with
 4        WITH T_WITH AS (SELECT '1' A FROM DUAL)
 5        --子查询使用t_with
 6          SELECT X.A,
 7                 (
 8                 --内部定义了个t_with_z,并且使用t_with
 9                 WITH T_WITH_Z AS (SELECT '1' A FROM T_WITH)
10                   SELECT S_1.A
11                     FROM T_WITH_Z S_1, T_WITH S_2) B
12                     FROM T_WITH X,
13                          --子查询中使用t_with,并且自己也定义了t_with_y
14                          (WITH T_WITH_Y AS (SELECT '1' A FROM T_WITH)
15                            SELECT F_1.A
16                              FROM T_WITH_Y F_1, T_WITH F_2) Y
17                             WHERE X.A = Y.A
18                                  --定义t_with_x
19                               AND X.A = (WITH T_WITH_X AS (SELECT '1' A
20                                                              FROM T_WITH)
21                              SELECT W_1.A
22                                FROM T_WITH_X W_1, T_WITH W_2))

复制代码

5、在列的子查询中引用WITH函数:

1 SELECT (WITH A AS (SELECT '1' FROM DUAL)
2          SELECT * FROM A) FROM DUAL

6、引用WITH查询结果:

1 SELECT *
2   FROM (WITH A AS (SELECT '1' FROM DUAL)
3          SELECT * FROM A)

 7、一个查询,如果查询的结果行不满足是5 的倍数,则补空行,直到是查询出的行数是5 的倍数。

1 WITH TEMP_DATA AS
2  (SELECT (5 - MOD(COUNT(*), 5)) COUNTS FROM DUAL CONNECT BY LEVEL < 3)
3 SELECT '1', '1'
4   FROM DUAL
5 UNION ALL
6 SELECT NULL, NULL FROM DUAL CONNECT BY LEVEL < (SELECT * FROM TEMP_DATA)

也可以使用ALL_OBJECTS

WITH TEMP_DATA AS
 (SELECT (5 - MOD(COUNT(*), 5)) COUNTS FROM DUAL CONNECT BY LEVEL < 3)
SELECT '1', '1'
  FROM DUAL
UNION ALL
SELECT NULL, NULL FROM ALL_OBJECTS WHERE ROWNUM < (SELECT * FROM TEMP_DATA)

 查询结果:

I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。

 

参考:

oracle with语句  百度

 

关于oracle with table as 创建临时表的用法示例以及使用with as 的优点

<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、付费专栏及课程。

余额充值