(Les17 Retrieving Data Using Subqueries)[20180103]
程序员文章站
2022-07-02 16:17:17
学习目标: -多列子查询 -SQL语句中使用标量子查询 -更新或删除行使用关联子查询 -使用EXISTS和NOT EXISTS操作符 -使用WITH子句 多列子查询 语法: Main query WHERE (,) IN Subquery; 列的比 ......
学习目标:
-多列子查询
-SQL语句中使用标量子查询
-更新或删除行使用关联子查询
-使用EXISTS和NOT EXISTS操作符
-使用WITH子句
多列子查询
语法:
Main query
WHERE (<column_name>,<column_name>) IN Subquery;
列的比较
-非成对比较(两两比较)
-成对比较
非成对比较 SELECT <column>,[<column>,| <column>] FROM <table_name> WHERE <column> IN Subquery AND <column> IN Subquery; 成对比较 SELECT <column>,[<column>,|<column>] FROM <table_name> WHRE (<column>,<column>) IN (SELECT <column>,<column> FROM <table_name> WHERE clause);
标量子查询 -标量子查询表达式中的子查询返回一个值 -标量子查询表达式中可以含有decode和case函数 -标量子查询中需排除GROUP BY -标量子查询可以在UPDATESQL语句SET子句中和WHERE条件 标量子查询不能用于: -列的默认值和集群的散列表达式 -DML语句RETURNING条件中 -基于函数的索引 -GROUP BY子句、CHECK约束和WHEN子句 -CONNECT BY子句 -与查询无关的语句中,如CREATE PROFILE概要文件
例子: SELECT <column>,<column> (CASE WHEN <column> = (SELECT <column> FROM <table_name> WHERE clause) THEN 'expression' END) <column_alias> FROM <table_name>;
关联子查询 -子查询引用主查询语句中的列值,Oracle执行相关子查询。 -对于主查询中的每一行,相关的子查询都会执行一次。 -主查询可以是SELECT/UPDATE或DELETE语句。 Nested Subqueries(嵌套子查询)或Correlated Subqueries(关联子查询) -嵌套子查询:子查询首先运行并执行一次,返回结果给主查询。 -关联子查询:关联子查询由外部的主查询驱动的,所以主查询中的每个列值子查询均会执行一次。 嵌套子查询执行顺序: -子查询执行一次并且返回一个值 -主查询使用子查询返回的值执行一次 关联子查询执行顺序: -主查询候选列值 -子查询使用主查询候选的列值运行并执行 -子查询值返回给主查询 -重复以上过程,直到没有候选列值
SELECT <columu1>,<column2>,.... FROM <table_name> outer WHERE <column1> operator (SELECT <column1>,<column2> FROM <table_name> WHERE expr1 = outer.expr2);
注意:关联子查询中可以使用ANY和ALL操作符
关联子查询效能验证与可替换方式:EXISTS/NO EXISTS操作符 -EXISTS运算符经常与相关的子查询一起使用,测试子查询检索的值的结果集中是否存在主查询检索的值。 -如果子查询返回至少一行,则该运算符返回TRUE。 如果该值不存在,则返回FALSE。 -NOT EXISTS测试主查询检索的值是否是子查询检索的值的结果集的一部分。
16:32:16 SQL> col last_name format a30 16:32:16 SQL> set pagesize 1200 16:32:16 SQL> select last_name,salary,department_id 16:32:16 2 from employees outer 16:32:16 3 where salary >(select avg(salary) 16:32:16 4 from employees 16:32:16 5 where department_id=outer.department_id) 16:32:16 6 ; LAST_NAME SALARY DEPARTMENT_ID ------------------------------ ---------- ------------- Hartstein 12990 20 Raphaely 10990 30 Weiss 7990 50 Fripp 8190 50 Kaufling 7890 50 Vollman 6490 50 Mourgos 5790 50 Ladwig 3590 50 Rajs 3490 50 Sarchand 4190 50 Bull 4090 50 Chung 3790 50 Dilly 3590 50 Bell 3990 50 Everett 3890 50
语句改写:
col last_name format a30 set pagesize 1200 select last_name,salary,department_id from employees outer where salary >(select avg(salary) from employees where department_id=outer.department_id) minus select outer.last_name,outer.salary,outer.department_id from employees outer,(select department_id,avg(salary) avg_salary from employees group by department_id) inner where outer.department_id=inner.department_id and outer.salary>inner.avg_salary; 对比两种写法: 16:45:11 SQL> set autotrace traceonly 16:45:21 SQL> alter system flush shared_pool; 已更改系統. 16:45:22 SQL> select last_name,salary,department_id 16:45:22 2 from employees outer 16:45:22 3 where salary >(select avg(salary) 16:45:22 4 from employees 16:45:22 5 where department_id=outer.department_id); --关联子查询 已選取 38 個資料列. 執行計畫 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=17 Bytes=6 97) 1 0 MERGE JOIN (Cost=11 Card=17 Bytes=697) 2 1 SORT (JOIN) (Cost=5 Card=11 Bytes=286) 3 2 VIEW OF 'VW_SQ_1' (VIEW) (Cost=5 Card=11 Bytes=286) 4 3 HASH (GROUP BY) (Cost=5 Card=11 Bytes=77) 5 4 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=4 Card=107 Bytes=749) 6 1 FILTER 7 6 SORT (JOIN) (Cost=5 Card=107 Bytes=1605) 8 7 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=4 C ard=107 Bytes=1605) 統計值 ---------------------------------------------------------- 351 recursive calls 0 db block gets 502 consistent gets 0 physical reads 0 redo size 1268 bytes sent via SQL*Net to client 449 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/from client 50 sorts (memory) 0 sorts (disk) 38 rows processed 16:45:23 SQL> alter system flush shared_pool; 已更改系統. 16:45:45 SQL> select outer.last_name,outer.salary,outer.department_id 16:45:45 2 from employees outer,(select department_id,avg(salary) avg_salary from employees grou department_id) inner 16:45:45 3 where outer.department_id=inner.department_id 16:45:45 4 and outer.salary>inner.avg_salary; --join连接查询 已選取 38 個資料列. 執行計畫 ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=17 Bytes=6 97) 1 0 MERGE JOIN (Cost=11 Card=17 Bytes=697) 2 1 SORT (JOIN) (Cost=5 Card=11 Bytes=286) 3 2 VIEW (Cost=5 Card=11 Bytes=286) 4 3 HASH (GROUP BY) (Cost=5 Card=11 Bytes=77) 5 4 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=4 Card=107 Bytes=749) 6 1 FILTER 7 6 SORT (JOIN) (Cost=5 Card=107 Bytes=1605) 8 7 TABLE ACCESS (FULL) OF 'EMPLOYEES' (TABLE) (Cost=4 C ard=107 Bytes=1605) 統計值 ---------------------------------------------------------- 191 recursive calls 0 db block gets 257 consistent gets 0 physical reads 0 redo size 1268 bytes sent via SQL*Net to client 449 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/from client 19 sorts (memory) 0 sorts (disk) 38 rows processed 16:45:46 SQL> JOIN连接查询比关联子查询性能上都有所提高。
SELECT <column1>,<colum2>,... FROM <table_name> outer WHERE [EXISTS | NOT EXISTS] (SELECT <column1>,<column2>,.... FROM <table_name> WHERE <column1> = outer.<column1>);
关联UPDATE
UPDATE <table_name> alias1 SET <column> = (SELECT expression FROM <table_name> alias2 WHERE alias1.column = alias2.column);
注意:关联UPDATE如果主查询选定值在子查询中未找到,SET栏位值将被更新成NULL值。
create table ORA_01407_T0( id number not null, name varchar2(10) not null ) / insert into ORA_01407_T0 values(1,'T01'); insert into ORA_01407_T0 values(2,'T02'); insert into ORA_01407_T0 values(3,'T03'); commit; create table ORA_01407_T1( id number not null, name varchar2(10) not null ) / insert into ORA_01407_T1 values(3,'T1_T03'); insert into ORA_01407_T1 values(4,'T1_T04'); commit; update ORA_01407_T0 a set a.name=(select name from ORA_01407_T1 b where a.id=b.id); 16:47:15 SQL> update ORA_01407_T0 a set a.name=(select name from ORA_01407_T1 b where a.id=b.id); update ORA_01407_T0 a set a.name=(select name from ORA_01407_T1 b where a.id=b.id) * ERROR 在行 1: ORA-01407: 無法將 ("HR"."ORA_01407_T0"."NAME") 更新為 NULL 將NAME NOT NULL約束去掉 17:12:55 SQL> ALTER TABLE HR.ORA_01407_T0 MODIFY(NAME NULL); 已更改表格. 17:12:58 SQL> update ORA_01407_T0 a set a.name=(select name from ORA_01407_T1 b where a 已更新 3 個資料列. 17:13:05 SQL> select * from ORA_01407_T0; ID NAME ---------- -------------------- 1 ->可以看到關聯查詢中不匹配的記錄name欄被賦值為NULL。 2 3 T1_T03
解決方案: 使用MERGE函數進行處理,匹配記錄UPDATE truncate table ORA_01407_T0; ALTER TABLE HR.ORA_01407_T0 MODIFY(NAME NOT NULL); insert into ORA_01407_T0 values(1,'T01'); insert into ORA_01407_T0 values(2,'T02'); insert into ORA_01407_T0 values(3,'T03'); commit; merge into ORA_01407_T0 a using ORA_01407_T1 b on (a.id=b.id) when matched then update set a.name=b.name ; 17:20:34 SQL> merge into ORA_01407_T0 a using ORA_01407_T1 b on (a.id=b.id) 17:21:48 2 when matched then update 17:21:48 3 set a.name=b.name 17:21:48 4 ; 合併 1 個資料列. 17:21:49 SQL> select * from ORA_01407_T0; ID NAME ---------- -------------------- 1 T01 2 T02 3 T1_T03
关联DELETE
10:51:14 SQL> select * from ora_01407_t0 10:51:41 2 ; ID NAME ---------- -------------------- 1 T01 2 T02 3 T1_T03 10:51:42 SQL> select * from ora_01407_t1; ID NAME ---------- -------------------- 3 T1_T03 4 T1_T04 10:51:46 SQL> delete 10:53:05 2 10:53:07 SQL> 10:53:07 SQL> 10:53:07 SQL> delete from ora_01407_t0 t1 10:53:10 2 where id=(select id from ora_01407_t1 t2 10:53:10 3 where t2.id=t1.id); 已刪除 1 個資料列. 10:53:11 SQL> select * from ora_01407_t0; ID NAME ---------- -------------------- 1 T01 2 T02
WITH子句 -使用WITH子句可以将多个相同的SELECT语句块组成一个复杂的查询 -WITH子句 中查询块返回值会保存在用户默认的临时表空间 -使用WITH子句可提高性能 WITH子句好处 -查询语句块便于阅读 -减少解析,查询块多次出现只会评估一次 -多数情况下,可提高查询性能 例子:查询部门薪水大于部门平均薪水的部门
col department_name format a20 with dept_costs as ( select d.department_name,sum(salary) as dept_total from employees e join departments d on e.department_id = d.department_id group by d.department_name), avg_cost as ( select sum(dept_total)/count(*) as dept_avg from dept_costs) select * from dept_costs where dept_total > (select dept_avg from avg_cost) order by department_name; DEPARTMENT_NAME DEPT_TOTAL -------------------- ---------- Sales 304160 Shipping 155950
学习总结: 1.多行/多列子查询(成对/非成对比较) 2.关联子查询(主查询->子查询->返回值->主查询)和标量子查询(返回一个列值)、关联UPDATE/DELETE/SELECT 3.EXISTS和NOT EXISTS操作符 4.使用WITH子句