OCP課程19:SQL之使用子查詢檢索資料
課程目標:
- 多列子查詢
- 標量子查詢
- 關聯子查詢
- exists運算子
- with語句
1
、多列子查詢
語法:
有2種多列比較:
- 非成對比較
- 成對比較,沒有交叉
例子:成對比較子查詢,查詢與姓為John的人員在同一部門且屬於同一上司的員工資訊
SQL> select employee_id,manager_id,department_id from employees where first_name='John';
EMPLOYEE_ID MANAGER_ID DEPARTMENT_ID
----------- ---------- -------------
110 108 100
145 100 80
139 123 50
SQL> select employee_id,manager_id,department_id from employees
2 where (manager_id,department_id) in(
3 select manager_id,department_id from employees where first_name='John')
4 and first_name<>'John';
EMPLOYEE_ID MANAGER_ID DEPARTMENT_ID
----------- ---------- -------------
137 123 50
15 rows selected.
例子:非成對比較子查詢,查詢與first_name為John的人員同一個部門同事以及與first_name為John的人員同一個上司的同事
SQL> select employee_id,manager_id,department_id from employees
2 where manager_id in(select manager_id from employees where first_name='John')
3 and department_id in(select department_id from employees where first_name='John')
4 and first_name<>'John';
EMPLOYEE_ID MANAGER_ID DEPARTMENT_ID
----------- ---------- -------------
120 100 50
20 rows selected.
2、標量子查詢表示式(scalar subquery)
只返回一個記錄的子查詢。
scalar subquery用於如下情況:
- decode和case的條件和表示式部分
- 沒有group by的select的語句
- update語句的set和where部分
例子:標量子查詢,當部門編號等於位置編號為1800的部門編號,則顯示位置為Canada,否則顯示USA
SQL> select employee_id,last_name,
2 (case when department_id=(select department_id from departments where location_id=1800)
3 then 'Canada' else 'USA' end) location
4 from employees;
EMPLOYEE_ID LAST_NAME LOCATI
----------- ------------------------- ------
198 OConnell USA
3、關聯子查詢
在關聯子查詢中,對於外部查詢返回的每一行資料,內部查詢都要執行一次。另外,在關聯子查詢中資訊流是雙向的。外部查詢的每行資料傳遞一個值給子查詢,然後子查詢為每一行資料執行一次並返回它的記錄。然後,外部查詢根據返回的記錄做出決策。
語法:
處理過程如下:
1)外查詢取出一行
2)從取出行中儲存子查詢需要的欄位
3)根據儲存的欄位執行子查詢
4)在外查詢where語句中對子查詢執行結果進行確認
5)重複執行以上過程
例子:查詢比部門平均薪水高的人員資訊
SQL> select last_name,salary,department_id from employees;
SQL> select department_id,avg(salary) from employees group by department_id;
SQL> select last_name,salary,department_id from employees outer
2 where salary>(select avg(salary) from employees where department_id=outer.department_id);
LAST_NAME SALARY DEPARTMENT_ID
------------------------- ---------- -------------
Fay 6000 10
例子:查詢職位變動過至少2次的人
SQL> select e.employee_id,last_name,e.job_id from employees e
2 where 2<=(select count(*) from job_history where employee_id=e.employee_id);
EMPLOYEE_ID LAST_NAME JOB_ID
----------- ------------------------- ----------
200 Whalen AD_ASST
4、exists運算子
比較子查詢的結果是否有記錄的存在,如果有記錄,則子查詢返回true且結束搜尋,如果沒有記錄,則子查詢返回false且繼續搜尋。
例子:查詢至少有一個下屬的領導資訊
SQL> select employee_id,last_name,job_id,department_id from employees outer
2 where exists(select 'X' from employees where manager_id=outer.employee_id);
EMPLOYEE_ID LAST_NAME JOB_ID DEPARTMENT_ID
----------- ------------------------- ---------- -------------
201 Hartstein MK_MAN 20
其中'X'是一個佔位符,沒有任何意義,使用數字也可以哦。
也可以使用in
SQL> select employee_id,last_name,job_id from employees outer
2 where employee_id in(select manager_id from employees where manager_id=outer.employee_id);
EMPLOYEE_ID LAST_NAME JOB_ID
----------- ------------------------- ----------
201 Hartstein MK_MAN
例子:查詢沒有人員的部門
SQL> select department_id,department_name from departments d
2 where not exists(select 1 from employees where department_id=d.department_id);
DEPARTMENT_ID DEPARTMENT_NAME
------------- ------------------------------
120 Treasury
SQL> select department_id,department_name from departments outer
2 where department_id not in (select department_id from employees where department_id is not null);
DEPARTMENT_ID DEPARTMENT_NAME
------------- ------------------------------
120 Treasury
SQL> select department_id,department_name from departments outer
2 where department_id not in(select department_id from employees where department_id=outer.department_id);
DEPARTMENT_ID DEPARTMENT_NAME
------------- ------------------------------
120 Treasury
5、關聯更新
使用關聯子查詢用一張表的資料對另一張表進行更新
語法:
例子:使用部門表的部門名字更新人員表的部門名字
SQL> create table empl6 as select * from employees;
Table created.
SQL> alter table empl6 add(department_name varchar2(25));
Table altered.
SQL> update empl6 e
2 set department_name=(select department_name from departments where department_id=e.department_id);
108 rows updated.
更新empl6表,將人員編號大於180的人員的部門名稱修改為abc,部門編號修改為500
SQL> update empl6 set department_name='abc',department_id=500 where employee_id>180;
27 rows updated.
SQL> commit;
Commit complete.
再次進行關聯更新
SQL> update empl6 e
2 set department_name=(select department_name from departments where department_id=e.department_id);
108 rows updated.
SQL> select department_name,department_id from empl6 where employee_id>180;
DEPARTMENT_NAME DEPARTMENT_ID
------------------------- -------------
500
500
500
可以看到這兒部門名稱被更新為null了,這兒要注意,如果子查詢裡面的表沒有對應的記錄,那麼更新的記錄會被置為null,而不是保持不變。那麼如果要使這些記錄保持不變,可以使用where語句加上條件只更新在departments表裡面有的部門名稱。
先回滾
SQL> rollback;
Rollback complete.
再來進行關聯更新
SQL> update empl6 e
2 set department_name=(select department_name from departments where department_id=e.department_id)
3 where exists(select department_name from departments where department_id=e.department_id);
80 rows updated.
檢視確認
SQL> select department_name,department_id from empl6 where employee_id>180;
DEPARTMENT_NAME DEPARTMENT_ID
------------------------- -------------
abc 500
6、關聯刪除
使用關聯子查詢用一張表的資料對另一張表進行刪除
語法:
例子:刪除表empl6裡面更換過工作的人員
SQL> delete from empl6 e
2 where employee_id in (select employee_id from job_history where employee_id=e.employee_id);
8 rows deleted.
SQL> select distinct employee_id from job_history;
EMPLOYEE_ID
-----------
101
8 rows selected.
7、with語句
- 儲存在使用者的臨時表空間
- 可以提高效能
- 只能用於select statements
- 可以包含多個查詢,用逗號分隔
- 先定義,後使用,對其後面的的查詢塊及主查詢可見
例子:使用with語句,查詢每個部門的名稱及其薪水總計,同時這些部門的薪水總計大於公司所有部門的平均薪水
使用with語句定義每個部門的薪水總計及所有部門的平均薪水
SQL> with
2 dept_costs as(
3 select d.department_name,sum(e.salary) as dept_total
4 from employees e join departments d on e.department_id=d.department_id
5 group by d.department_name),
6 avg_cost as(
7 select sum(dept_total)/count(*) as dept_avg from dept_costs)
8 select * from dept_costs where dept_total>(select dept_avg from avg_cost) order by department_name;
DEPARTMENT_NAME DEPT_TOTAL
------------------------------ ----------
Sales 304500
Shipping 206400
檢視他的執行計劃,建立了一個臨時表,提高了效能
SQL> explain plan for
2 with
3 dept_costs as(
4 select d.department_name,sum(e.salary) as dept_total
5 from employees e join departments d on e.department_id=d.department_id
6 group by d.department_name),
7 avg_cost as(
8 select sum(dept_total)/count(*) as dept_avg from dept_costs)
9 select * from dept_costs where dept_total>(select dept_avg from avg_cost) order by department_name;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3967601111
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 27 | 810 | 12 (25)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6610_25A4FE | | | | |
| 3 | HASH GROUP BY | | 27 | 621 | 7 (29)| 00:00:01 |
| 4 | MERGE JOIN | | 107 | 2461 | 6 (17)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
| 6 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)| 00:00:01 |
|* 7 | SORT JOIN | | 108 | 756 | 4 (25)| 00:00:01 |
| 8 | TABLE ACCESS FULL | EMPLOYEES | 108 | 756 | 3 (0)| 00:00:01 |
| 9 | SORT ORDER BY | | 27 | 810 | 5 (20)| 00:00:01 |
|* 10 | VIEW | | 27 | 810 | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6610_25A4FE | 27 | 621 | 2 (0)| 00:00:01 |
| 12 | VIEW | | 1 | 13 | 2 (0)| 00:00:01 |
| 13 | SORT AGGREGATE | | 1 | 13 | | |
| 14 | VIEW | | 27 | 351 | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6610_25A4FE | 27 | 621 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
10 - filter("DEPT_TOTAL"> (SELECT "DEPT_AVG" FROM (SELECT SUM("DEPT_TOTAL")/COUNT(*) "DEPT_AVG"
FROM (SELECT /*+ CACHE_TEMP_TABLE ("T1") */ "C0" "DEPARTMENT_NAME","C1" "DEPT_TOTAL" FROM
"SYS"."SYS_TEMP_0FD9D6610_25A4FE" "T1") "DEPT_COSTS") "AVG_COST"))
8、相關習題:
(1)Which two statements are true regarding the execution of the correlated subqueries ?(Choose two)
A.The nested query executes after the outer query returns the row.
B.The nested query executes first and then the outer query executes.
C.The outer query executes only once for the result returned by the inner query.
D.Each row returned by the outer query is evaluated for the results returned by the inner query.
答案:AD
(2)Which two statements are true regarding the EXISTS operator used in the correlated subqueries?(choose two)
A.The outer query stops evaluating the result set of the inner query when the first value is found.
B.It is used to test whether the values retrieved by the inner query exist in the result of the outer query.
C.It is used to test whether the values retrieved by the outer query exist in the result set of the inner query.
D.The outer query continues evaluating the result set of the inner query until all the values in the result set are processed.
答案:AC
(3)View the Exhibit and examine the description of EMPLOYEES and DEPARTMENTS tables. You want to display the EMPLOYEE_ID, LAST_NAME, and SALARY for the employees who get the maximum salary in their respective departments. The following SQL statement was written: WITH SELECT employee_id, last_name, salary FROM employees WHERE (department_id, salary) = ANY (SELECT * FROM dept_max) dept_max as ( SELECT d.department_id, max(salary) FROM departments d JOIN employees j ON (d.department_id = j.department_id) GROUP BY d.department_id)? Which statement is true regarding the execution and the output of this statement?
A.The statement would execute and give the desired results.
B.The statement would not execute because the = ANY comparison operator is used instead of =.
C.The statement would not execute because the main query block uses the query name before it is even created.
D.The statement would not execute because the comma is missing between the main query block and the query name
答案:C
(4)View the Exhibit and examine DEPARTMENTS and the LOCATION tables. Evaluate the following SQL statement: SELECT location_id, city FROM locations l WHERE NOT EXISTS (SELECT location_id FROM departments WHERE location_id <> l.location_id)? This statement was written to display LOCATION_ID and CITY where there are no departmnts located. Which statement is true regarding the execution and output of the command?
A.The statement would execute and would return the desired results.
B.The statement would not execute because the = comparison operator is missing in the WHERE clause of the outer query.
C.The statement would execute but it will return zero rows because the WHERE clause in the inner query should have the = operator instead of <>.
D.The statement would not execute because the WHERE clause in the outer query is missing the column name for comparison with the inner query result.
答案:C
(5)The following are the steps for a correlated subquery, listed in random order: 1) The WHERE clause of the outer query is evaluated. 2) The candidate row is fetched from the table specified in the outer query. 3) The procedure is repeated for the subsequent rows of the table, till all the rows are processed. 4) Rows are returned by the inner query, after being evaluated with the value from the candidate row in the outer query. Identify the option that contains the steps in the correct sequence in which the Oracle server evaluates a correlated subquery.
A.4, 2, 1, 3
B.4, 1, 2, 3
C.2, 4, 1, 3
D.2, 1, 4, 3
答案:C
(6)Which two statements best describe the benefits of using the WITH clause?(Choose two.)
A.It enables users to store the results of a query permanently.
B.It enables users to store the query block permanently in the memory and use it to create complex queries.
C.It enables users to reuse the same query block in a SELECT statement, if it occurs more than once in a complex query.
D.It can improve the performance of a large query by storing the result of a query block having the WITH clause in the user's temporary tablespace.
答案:CD
(7)Which statements are true regarding the usage of the WITH clause in complex correlated subqueries?(Choose all that apply.)
A.It can be used only with the SELECT clause.
B.The WITH clause can hold more than one query.
C.If the query block name and the table name were the same, then the table name would take precedence.
D.The query name in the WITH clause is visible to other query blocks in the WITH clause as well as to the main query block.
答案:ABD
(8)View the Exhibit and examine the structure of EMPLOYEES and JOB_HISTORY tables. The EMPLOYEES table maintains the most recent information regarding salary, department, and job for all the employees. The JOB_HISTORY table maintains the record for all the job changes for the employees. You want to delete all the records from the JOB_HISTORY table that are repeated in the EMPLOYEES table. Which two SQL statements can you execute to accomplish the task?(Choose two.)
A.DELETE FROM job_history j WHERE employee_id = (SELECT employee_id FROM employees e WHERE j.employee_id = e.employee_id) AND job_id = (SELECT job_id FROM employees e WHERE j.job_id = e.job_id);
B.DELETE FROM job_history j WHERE (employee_id, job_id) = ALL (SELECT employee_id, job_id FROM employees e WHERE j.employee_id = e.employee_id and j.job_id = e.job_id );
C.DELETE FROM job_history j WHERE employee_id = (SELECT employee_id FROM employees e WHERE j.employee_id = e.employee_id and j.job_id = e.job_id );
D.DELETE FROM job_history j WHERE (employee_id, job_id) = (SELECT employee_id, job_id FROM employees e WHERE j.employee_id = e.employee_id and j.job_id = e.job_id );
答案:CD
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28536251/viewspace-1876336/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- OCP課程8:SQL之使用子查詢SQL
- Oracle OCP(14):使用子查詢檢索資料Oracle
- OCP課程3:SQL之使用SELECT語句檢索資料SQL
- 使用子查詢檢索資料
- OCP課程20:SQL之分層查詢SQL
- OCP課程7:SQL之多表查詢SQL
- OCP課程13:SQL之使用資料字典檢視管理物件SQL物件
- ORACLE_OCP之SQL_子查詢OracleSQL
- Oracle OCP(01):使用SQL SELECT語句檢索資料OracleSQL
- OCP課程9:SQL之使用集合運算子SQL
- OCP課程6:SQL之使用組函式SQL函式
- OCP課程5:SQL之使用單行函式SQL函式
- Oracle OCP(08):使用子查詢Oracle
- OCP課程16:SQL之處理大資料SQL大資料
- OCP課程4:SQL之限制和排序資料SQL排序
- 使用SQL SELECT語句檢索資料SQL
- OCP課程14:SQL之控制使用者訪問SQL
- OCP課程56:管理II之SQL調優SQL
- OCP課程15:SQL之管理模式物件SQL模式物件
- OCP課程21:SQL之正規表示式SQL
- OCP課程12:SQL之建立其他模式物件SQL模式物件
- OCP課程11:SQL之使用DDL語句建立和管理表SQL
- OCP課程25:管理Ⅰ之使用DBCA建立資料庫資料庫
- OCP課程18:SQL之管理不同時區下的資料SQL
- sql子查詢SQL
- RAC:在子查詢使用gv$檢視,有時查詢不出資料
- OCP課程53:管理II之使用閃回資料庫資料庫
- SQL Server之查詢檢索操作SQLServer
- OCP課程39:管理Ⅰ之移動資料
- SQL查詢的:子查詢和多表查詢SQL
- SQL--子查詢SQL
- SQL -- 使用聯結還是子查詢?SQL
- SQL入門之4 group by 與子查詢SQL
- 【SQL】Oracle查詢轉換之物化檢視查詢重寫SQLOracle
- OCP課程24:管理Ⅰ之資料庫安裝資料庫
- 【MySQL】檢視&子查詢MySql
- C#實現SQL全庫檢索資料C#SQL
- Sql Server系列:子查詢SQLServer