oracle高級sql的參考資料

 1.集合操作
學習oracle中集合操作的有關語句,掌握union,union all,minus,interest的使用,能夠描述結合運算,並且能夠將多個查詢組合到一個查詢中去,能夠控制行返回的順序。
包含集合運算的查詢稱爲複合查詢。見表格1-1
表1-1
Operator         Returns         content
UNION         由每個查詢選擇的所有不重複的行          並集不包含重複值
UNION ALL         由每個查詢選擇的所有的行,包括所有重複的行         完全並集包含重複值
INTERSECT         由每個查詢選擇的所有不重複的相交行          交集
MINUS         在第一個查詢中,不在後面查詢中,並且結果行不重複          差集

所有的集合運算與等號的優先級相同,如果SQL語句包含多個集合運算並且沒有圓括號明確地指定另一個順序,Oracle服務器將以從左到右的順序計算。你應該使用圓括號來明確地指定帶另外的集合運算的INTERSECT (相交) 運算查詢中的賦值順序。
Union all 效率一般比union高。
1.1.union和union all
UNION(聯合)運算
UNION運算返回所有由任一查詢選擇的行。用UNION運算從多表返回所有行,但除去任何重複的行。
原則 :

􀂃被選擇的列數和列的數據類型必須是與所有用在查詢中的SELECT語句一致。列的名字不必相同。
􀂃聯合運算在所有被選擇的列上進行。
􀂃在做重複檢查的時候不忽略空(NULL)值。
􀂃IN運算有比UNION運算高的優先級。
􀂃在默認情況下,輸出以SELECT子句的第一列的升序排序。

全聯合(UNION ALL)運算
用全聯合運算從多個查詢中返回所有行。
原則

􀂃和聯合不同,重複的行不被過濾,並且默認情況下輸出不排序。
􀂃不能使用DISTINCT關鍵字。
使用:
Select statement union | union all Select statement;

1.2.intersect交集操作
相交運算
用相交運算返回多個查詢中所有的公共行。 無重複行。
原則

􀂃在查詢中被 SELECT 語句選擇的列數和數據類型必須與在查詢中所使用的所有的 SELTCT 語句中的一樣,但列的名字不必一樣。
􀂃相交的表的倒序排序不改變結果。
􀂃相交不忽略空值。
使用:
Select statement intersect all Select statement;

1.3. minus差集操作
相減運算
用相減運算返回由第一個查詢返回的行,那些行不出現在第二個查詢中 (第一個SELECT語句減第二個SELECT語句)。
原則

􀂃在查詢中被SELECT語句選擇的列數和數據類型必須與在查詢中所使用的所有的SELTCT語句中的一樣,但列的名字不必一樣。
􀂃對於MINUS運算,在WHERE子句中所有的列都必須在SELECT子句中。


集合運算的原則
•在兩個SELECT列表中的表達式必須在數目上和數據類型上相匹配
•可以用圓括號改變執行的順序
•ORDER BY子句:–只能出現在語句的最後–從第一個SELECT語句接收列名、別名,或者位置記號

注:•除了UNION ALL,重複行自動被清除
•在結果中的列名是第一個查詢中出現的列名
•除了UNION ALL,默認情況下按升序順序輸出
2.exists和not exists的使用
2.1. exists的使用
Exists用於只能用於子查詢,可以替代in,若匹配到結果,則退出內部查詢,並將條件標誌爲true,傳回全部結果資料,in不管匹配到匹配不到都全部匹配完畢,使用exists可以將子查詢結果定爲常量,不影響查詢效果,而且效率高。如查詢所有銷售部門員工的姓名,對比如下:
IN is often better if the results of the subquery are very small
When you write a query using the IN clause, you're telling the rule-based optimizer that you want the inner query to drive the outer query.
When you write EXISTS in a where clause, you're telling the optimizer that you want the outer query to be run first, using each value to fetch a value from the inner query.
In many cases, EXISTS is better because it requires you to specify a join condition, which can invoke an INDEX scan. However, IN is often better if the results of the subquery are very small. You usually want to run the query that returns the smaller set of results first.


In和exists對比:
若子查詢結果集比較小,優先使用in,若外層查詢比子查詢小,優先使用exists。因爲若用in,則oracle會優先查詢子查詢,然後匹配外層查詢,若使用exists,則oracle會優先查詢外層表,然後再與內層表匹配。最優化匹配原則,拿最小記錄匹配大記錄。
使用in
select last_name, title
        from s_emp
        where dept_id in
                (select id
                from s_dept
                where name='Sales');        

使用exists
select last_name,title
       from s_emp e
       where  exists
       (select 'x' --把查詢結果定爲constant,提高效率
        from s_dept s where s.id=e.dept_id and s.name='Sales');
2.2 not exists的使用
        與exists 含義相反,也在子查詢中使用,用於替代not in。其他一樣。如查詢不在銷售部的員工姓名
select last_name,title
       from s_emp e
       where  not exists
       (select 'x' --把查詢結果定爲constant,提高效率
        from s_dept s where s.id=e.dept_id and s.name='Sales');
3.with子句
9i新增語法
1.使用with子句可以讓子查詢重用相同的with查詢塊,通過select調用,一般在with查詢用到多次情況下。

2.with子句的返回結果存到用戶的臨時表空間中,只做一次查詢,提高效率。

3.有多個查詢的時候,第1個用with,後面的不用with,並且用逗號隔開。

5.最後一個with子句與下面的查詢之間不能有逗號,只通過右括號分割,查詢必須用括號括起來

6.如果定義了with子句,而在查詢中不使用,那麼會報ora-32035錯誤:未引用在with子句中定義的查詢名。(至少一個with查詢的name未被引用,解決方法是移除未被引用的with查詢)

7.前面的with子句定義的查詢在後面的with子句中可以使用。
With子句目的是爲了重用查詢。

語法:
With alias_name as (select1), --as和select中的括號都不能省略
alias_name2 as (select2),--後面的沒有with,逗號分割

alias_namen as (select n) –與下面的查詢之間沒有逗號
Select ….
如查詢銷售部門員工的姓名:
  --with clause
with a as
     (select id from s_dept where name='Sales' order by id)
  select last_name,title
         from s_emp where dept_id in (select * from a);--使用select查詢別名

使用with子句,可以在複雜的查詢中預先定義好一個結果集,然後在查詢中反覆使用,不使用會報錯。而且with子句獲得的是一個臨時表,如果在查詢中使用,必須採用select  from with查詢名,比如
With cnt as(select count(*) from table)
Select cnt+1 from dual;
是錯誤的。必須是
   With cnt as(select count(*) shumu from user_tables)
Select shumu+1 from cnt;
--直接引用with子查詢中的列別名。

        一個with查詢的實例:
        查詢出部門的總薪水大於所有部門平均總薪水的部門。部門表s_dept,員工表s_emp。
分析:做這個查詢,首先必須計算出所有部門的總薪水,然後計算出總薪水的平均薪水,再篩選出部門的總薪水大於所有部門總薪水平均薪水的部門。那麼第1步with查詢查出所有部門的總薪水,第2步用with從第1步獲得的結果表中查詢出平均薪水,最後利用這兩次的with查詢比較總薪水大於平均薪水的結果,如下:
with
--step1:查詢出部門名和部門的總薪水
dept_costs as(
            select a.name,sum(b.salary) dept_total
              from
                      s_dept a,s_emp b
                     where a.id=b.dept_id
                     group by a.name
),
--step2:利用上一個with查詢的結果,計算部門的平均總薪水
avg_costs as(
           select sum(dept_total)/count(*) dept_avg
            from dept_costs         
)
--step3:從兩個with查詢中比較並且輸出查詢結果
select name,dept_total
  from dept_costs
  where
   dept_total>
    (
     select dept_avg
      from
     avg_costs
    )
   order by name;

從上面的查詢可以看出,前面的with查詢的結果可以被後面的with查詢重用,並且對with查詢的結果列支持別名的使用,在最終查詢中必須要引用所有with查詢,否則會報錯ora-32035錯誤。



再如有這樣一個需求:一個查詢,如果查詢的結果行不滿足是10的倍數,則補空行,直到是查詢出的行數是10的倍數。例如:select * from trademark這個查詢。
with cnt as (select 10-mod(count(*),10) shumu from trademark) –查詢比10的倍數差幾個空行
select id,name
  from trademark
union all        --空行加進去
select null,null  --補空行
from dual connect by rownum<=(select shumu from cnt); --10箇中connect by可以使用子查詢
10g之前的寫法
with cnt as (select 10-mod(count(*),10) shumu from trademark) –查詢比10的倍數差幾個空行
select id,name
  from trademark
union all        --空行加進去
select null,null  --補空行
from all_objects where rownum<=(select shumu from cnt);--使用all_objects行比較多



4.merge into合併資料
語法:(其中as可以省略)
MERGE INTO table_name AS table_alias
USING (table|view|sub_query) AS alias
ON (join condition)
WHEN MATCHED THEN
UPDATE SET
col1 = col_val1,
col2 = col2_val
WHEN NOT MATCHED THEN
INSERT (column_list)—多個列以逗號分割                      //可以不指定列
VALUES (column_values);

作用:將源數據(來源於實際的表,視圖,子查詢)更新或插入到指定的表中(必須實際存在),依賴於on條件,好處是避免了多個insert和update操作。Merge是一個目標性明確的操作符,不允許在一個merge語句中對相同的行insert或update操作。這個語法僅需要一次全表掃描就完成了全部工作,執行效率要高於INSERT+UPDATE。例子如下:

drop table t;
CREATE TABLE T AS SELECT ROWNUM ID, A.* FROM DBA_OBJECTS A;

drop table t1;
CREATE TABLE T1 AS
SELECT ROWNUM ID, OWNER, TABLE_NAME, CAST('TABLE' AS VARCHAR2(100)) OBJECT_TYPE
FROM DBA_TABLES;


select *  from dba_objects;
select *  from dba_tables;

MERGE INTO T1 USING T
ON (T.OWNER = T1.OWNER AND T.OBJECT_NAME = T1.TABLE_NAME AND T.OBJECT_TYPE = T1.OBJECT_TYPE)
WHEN MATCHED THEN UPDATE SET T1.ID = T.ID
WHEN NOT MATCHED THEN INSERT VALUES (T.ID, T.OWNER, T.OBJECT_NAME, T.OBJECT_TYPE);--insert後面不寫表示插入全部列


MERGE INTO T1 USING T
ON (T.OWNER = T1.OWNER AND T.OBJECT_NAME = T1.TABLE_NAME)
WHEN MATCHED THEN UPDATE SET T1.ID = T.ID
WHEN NOT MATCHED THEN INSERT VALUES (T.ID, T.OWNER, T.OBJECT_NAME, T.OBJECT_TYPE);--常見錯誤,連接條件不能獲得穩定的行,可以使用下面的用子查詢


MERGE INTO T1
USING (SELECT OWNER, OBJECT_NAME, MAX(ID) ID FROM T GROUP BY OWNER, OBJECT_NAME) T
ON (T.OWNER = T1.OWNER AND T.OBJECT_NAME = T1.TABLE_NAME)
  WHEN MATCHED THEN UPDATE SET T1.ID = T.ID
WHEN NOT MATCHED THEN INSERT VALUES (T.ID, T.OWNER, T.OBJECT_NAME);


SELECT ID, OWNER, OBJECT_NAME, OBJECT_TYPE FROM T
MINUS
SELECT * FROM T1;

drop table subs;
create table subs(msid number(9),
                    ms_type char(1),
                  areacode number(3)
                    );
                    
     drop table acct;               
                     create table acct(msid number(9),
                     bill_month number(6),
                    areacode   number(3),
                    fee        number(8,2) default 0.00);
                    
insert into subs values(905310001,0,531);
insert into subs values(905320001,1,532);
insert into subs values(905330001,2,533);                 
commit;

merge into acct a --操作的表
      using subs b on (a.msid=b.msid)--使用原始數據來源的表,並且制定條件,條件必須有括號
     when matched then
          update set a.areacode=b.areacode--當匹配的時候,執行update操作,和直接update的語法不一樣,不需要制定表名
     when not matched then--當不匹配的時候,執行insert操作,也不需要制定表名,若指定字段插入,則在insert後用括號標明,不指定是全部插入
          insert(msid,bill_month,areacode) values(b.msid,'200702',b.areacode);
         
   
   
另外,MERGE語句的UPDATE不能修改用於連接的列,否則會報錯
select *  from acct;
select * from subs;
--10g新特性,單個操作
merge into acct a
      using subs b on(a.msid=b.msid)
    when not matched then--只有單個not matched的時候,只做插入,不做更新,只有單個matched的時候,只做更新操作
         insert(a.msid,a.bill_month,a.areacode) values(b.msid,'200702',b.areacode);
         
update acct set areacode=800 where msid=905320001;

delete from acct where areacode=533 or areacode=531;

insert into acct values(905320001,'200702',800,0.00);


--刪除重複行
delete from subs b where b.rowid<(
select max(a.rowid) from subs a where a.msid=b.msid and a.ms_type=b.ms_type and a.areacode=b.areacode);

--10g新特性,merge操作之後,只有匹配的update操作纔可以,用delete where子句刪除目標表中滿足條件的行。
  merge into acct a
     using subs b on (a.msid=b.msid)
   when MATCHED then
        update set a.areacode=b.areacode        
        delete where (b.ms_type!=0)
        when NOT MATCHED then
        insert(msid,bill_month,areacode)
        values(b.msid,'200702',b.areacode)
        where b.ms_type=0;
  --10g新特性,滿足條件的插入和更新         
merge into acct a
     using subs b on (a.msid=b.msid)     
   when MATCHED then
        update set a.areacode=b.areacode
        where b.ms_type=0
   when NOT MATCHED then
        insert(msid,bill_month,areacode)
        values(b.msid,'200702',b.areacode)
        where b.ms_type=0;

select *  from subs where ms_type=0;
[size=10.5pt]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章