欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(Les17 Retrieving Data Using Subqueries)[20180103]

程序员文章站 2022-03-29 21:22: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语句。  (Les17 Retrieving Data Using Subqueries)[20180103]         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操作符                     
关联子查询效能验证与可替换方式:
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连接查询比关联子查询性能上都有所提高。
      EXISTS/NO EXISTS操作符         -EXISTS运算符经常与相关的子查询一起使用,测试子查询检索的值的结果集中是否存在主查询检索的值。         -如果子查询返回至少一行,则该运算符返回TRUE。 如果该值不存在,则返回FALSE。          -NOT EXISTS测试主查询检索的值是否是子查询检索的值的结果集的一部分。        
 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子句