Oracle 原理:複雜的SQL語句

1.select [列名] from [表名] where [條件] group by [列名] having [條件] order by [列名]  的執行順序。

 在查詢裏面, 首先執行 from 來需要確定表,然後一條一條地遍歷表數據;執行where語句把符合的表數據行篩選數來,也就得到了可以輸出的數據;之後,將篩選出來的數據進行group by分組;之後用having來確定哪些數據不顯示;之後,用orderby來對顯示數據的數據進行排序。 

------------------------------------------------------分割線------------------------------------------------

有如下的  工資表(僱員名稱,所屬部門,薪資,部門組長);

drop table salary_tbl;
create table salary_tbl(
   employer_nm varchar(20),
   department varchar(20) not null,
   salary number not null,
   leader_nm varchar(20)
);
truncate table salary_tbl;
begin
 for i in  1..100
     loop
     insert into salary_tbl values('僱傭者'||i,'部門'||Mod(i,6),100*POWER(10000,i*0.01),'僱傭者'||Mod(i,6)); 
   end loop;
end;
/ 
commit;

 

寫SQL一般先確定表和表之間的關聯關係,然後列出篩選條件個數,例如,查詢最高薪資的部門組長信息

①確認要查詢的表爲 salary_tbl   ② 篩選條件兩個:要爲部門組長,在組長裏薪資最高

------查詢薪資最高的部門組長-----
select * from salary_tbl s where
EMPLOYER_NM in (select distinct LEADER_NM from salary_tbl)  --條件1:部門組長信息確定
and salary =(select max(salary) from salary_tbl s where     --條件2: 薪資爲部門組長裏最高的
EMPLOYER_NM in (select distinct LEADER_NM from salary_tbl));

對於複雜的增刪改語句中也是一樣的思路,首先確定表和表之間的關聯關係,確定要修改的字段,把篩選條件一一列舉出來就可以思路清晰地實現了

2.集合運算 union(並集),minus(差集),intersect(交集)

  Where 後面的條件篩選 也可以用集合運算來實現。

---------查詢薪資低於150塊錢部門組長信息(兩次)---------
select s.* from (select * from salary_tbl where EMPLOYER_NM=leader_nm) s  
minus
select * from salary_tbl where salary>=150       --部門組長表和薪資大於150的差集
UNION ALL                --不去重聯合查詢
select s3.* from 
(select s.* from (select * from salary_tbl where EMPLOYER_NM=leader_nm) s
INTERSECT
select * from salary_tbl where salary<150) s3;   --部門組長表和薪資小於150的交集

3.  rownum 和 Rowid

 rownum和rowid 在查詢時都不是直接展示的。其中rownum即行標,在執行完SQL查詢時後面添加上去的,所以每條數據的rownum根據不同的篩選條件是會變的,而rowId是由該數據行的物理地址信息所組成的字段。如果數據的物理位置沒變,那麼rowid也就不會變,當查詢語句沒跟order by時,默認按rowId排序。如圖

當把rownum當做篩選條件時 只有 rownum < 或者 rownum <= 才能起效果,而大於,等於,不等於,between都不能有效的當做篩選條件。例如查詢該表中的最後5行數據

---------------
select * from 
(select salary_tbl.* ,rownum as row_num,rowID as row_id from salary_tbl) s
where s.row_num  between (select count(1) from salary_tbl )-5 and (select count(1) from salary_tbl);
----------------
select s.*,rownum from salary_tbl s
minus
select salary_tbl.*,rownum  from salary_tbl where rownum<
(select count(1) from salary_tbl )-5;

4. case when..then....else  和decode(value,if1,then1,if2,then2,if3,then3,...,else)

 case when...then ..else  和decode 很像面向對象程序語言裏的  if...elseif...elseif ..else 語句,但是decode裏的 if條件只能用來判斷相等,而不能直接的進行比大小。

select s.employer_nm,
       s.department,
       case when s.salary<1000 then '窮鬼'
            when salary<8000   then '正常'
            when salary <40000 then '牛逼'
            else '大佬'   
       end as 薪資水平,
       s.leader_nm from salary_tbl s
-----------
select s.employer_nm,
       s.department,
       decode(sign(salary-10000),1,'高',-1,'低','剛好一萬元') as 薪資高低,
       s.leader_nm from salary_tbl s

  5. 變量,行變量,遊標

例子:下面是輸出    查詢表中的最後5行數據

declare 
   max_num number;
   rowdata salary_tbl%rowtype;     --行類型變量
   type cur_type is ref cursor;    
   output1 cur_type ;              --遊標
   v_sql varchar2(2000) :=''; 
   begin 
    select count(1) into max_num from salary_tbl;   -- 給變量賦值
    v_sql :='select s.employer_nm,s.department,s.salary,s.leader_nm from 
            (select salary_tbl.*, rownum as row_num from salary_tbl) s where 
            s.row_num  between '|| (max_num-5)||' and '||max_num;    --記得單詞間的空格,不用加分號
             
    open output1 for v_sql;     
    
    LOOP
      fetch output1 into rowdata; 
      exit when output1%notfound;
      dbms_output.put_line(rowdata.employer_nm || '|@|' ||
                           rowdata.department  || '|@|' ||
                           rowdata.salary      || '|@|' ||
                           rowdata.leader_nm);
    END LOOP;            --循環輸出
   end;

輸出結果::

 

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