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)

 查詢結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM