1. 程式人生 > 資料庫 >碎點篇—— oracle 語法和練習

碎點篇—— oracle 語法和練習

返回主目錄

 

--select from where having group by order by 的正確執行順序為:
--from-->where-->group by-->having-->select-->order by
--------------------------------------------------------
--1、去重:distinct 必須放在開頭,多欄位,每個欄位不一樣才去重
--2、條件比較:
-- =,!=,<>,<,>,<=,>=,any,some,all
-- is null,is not null
-- between x and y
-- in(list),not in (list)
-- like _,%,escape '\' _\%escape '\'
-- not,(and,or) and優先順序高

-- 按照單個列排序
-- order by col
-- 降序排列:order by col desc
-- 升序排列:order by col asc
-- 按多個列排序:(優先順序)
-- order by col1 desc(asc),col2 desc(asc)

--1.全集:union all
--2.並集:union (去重)
--3.交集:intersect
--4.差集:minus
--5.不懂怎麼用,就選擇 (*)
-----------------------------------------------------------
--基本查詢語句
select * from emp;
select e.ename,e.sal from emp e where e.sal>1500;
select distinct e.deptno,d.dname from emp e,dept d;
---------------------------------------------------------
--組函式又被稱作集合函式,用於對多行資料進行操作,並返回一個單一的結果
--組函式僅用於選擇列表或查詢的having子句單行函式對單個數值進行操作,並
--返回一個值。
--concat(string2,string3)連線兩個字串
--initcap(string) string中每個單詞首字母大寫
--lower(string) string 中每個單詞首字母小寫
--lpad,rpad 填充字元型資料
--ltrim/rtrim (string2,string3)
trim(A from B)
--substr() 提取字串的一部分substr(string,1,2)
--upper(string)以大寫形式返回string
--instr() 字串出現的位置,instr(string,'A')
--length() 字串長度

-------------------------------------------------------
--round(number,n):返回四捨五入的值
select round(23.434) from dual;
select round(23.434,2) from dual;
select round(23.436,2) from dual;
select round(23.434,-1) from dual;
--trunc(number,n): 返回擷取的值
select trunc(23.434) from dual;
select trunc(23.434,2) from dual;
select trunc(23.436,2) from dual;
select trunc(23.434,-1) from dual;
--mod(x,y):求餘數
select mod(13,5) from dual;
--ceil(number):向上取整
select ceil (19.2) from dual;
--floor(number):向下取整
select floor(19.2) from dual;

--avg(): 返回某列的平均值
--min(): 返回某列的最小值
--max(): 返回某列的最大值
--sum(): 返回某列值的和
--count(): 返回某列的行數
--組函式僅在選擇列表和having子句中有效

--group by 子句
--group by 子句可以包含任意數目的列
--除組函式語句外,select 語句中的每個列都必須在 group by 子句中給出。
--如果分組列中具有null值,則null將作為一個分組返回。如果列中有多行null
--值,他們將分為一組。
--group by 子句必須出現在where 子句之後,order by 子句之前。
--過濾分組(having子句)
--where 過濾行,
--having 過濾分組
--having 支援所有的where操作
--分組和排序
--一般在使用group by 子句時,應該給出 order by 子句

--資料來自於多張表,92表連線
--注意:明確引用同名的列,必須使用表名,或者別名區分
--1.笛卡爾積:
--   select 欄位列表 from 表1,表2,表3....
--2.等值連線:取關係列相同的記錄
--   select 欄位列表 from 表1,表3....
--          where 表1.列 = 表2.列 and 表1.列 =表3.列
--3.非等值連線:取關係列不同的記錄 != > < >= <= between and
--   select 欄位列表 from 表1,表3....
--          where 表1.列 != 表2.列 and 表1.列 != 表3.列
--4.自連線:(特殊的等值連線) 列來自於同一張表,不同角度看待表
--   select 欄位列表 from 表1 e,表2 d 
--          where e.列1 = d.列3
--5.外連線:在等值基礎上,確保一張表(主表) 的記錄都存在,從
--          表滿足則匹配,不滿足補充null
--右外:主表在右邊
--左外:主表在左邊

--sql1992:的語法規則暴露了這樣額缺點:語句過濾條件和表連線的條件
--          都放到了where子句中。當條件過多時,聯結條件多,過濾條件
--          多時,就容易造成混淆
--sql1999:修正了這個缺點,把聯結條件,過濾條件分開來,包括以下新的table
--          join 的句法結構:
--cross join
--natural join 
--using 子句
--on 子句
--left outer join
--right outer join
--full outer join
-------------------------------------------------------
--建立檢視
--with read only 表示只讀
create or replace view v_emp_dept_a as 
       select e.deptno,e.ename,d.dname from
       emp e join dept d on e.deptno= d.deptno
       with read only ;

select * from v_emp_dept_a;
--當不再需要檢視的時候,用"drop view"撤銷。刪掉檢視不會導致資料的丟失
--因為檢視是基於資料庫的表之上的一個查詢定義
drop view v_emp_dept_a;

--建立檢視必須要有主鍵,不然無法插入資料。
create or replace view v_emp_dept_b as
       select e.empno,e.sal,e.deptno from emp e;

select * from v_emp_dept_b;

--DML
insert into v_emp_dept_b (empno,ename,sal) values(2000,'zhiyi',3554);
update v_emp_dept_b set ename='weiwo',deptno=20 where ename='zhiyi';
delete from v_emp_dept_b where ename like 'weiwo'
-----------------------------------------------------------------------
--我們要求平均薪水的等級最低的部門,它的部門名稱是什麼?
--我們完全使用子查詢
--求部門的平均薪水
select e.deptno dt,avg(e.sal) avg_sal from emp e group by deptno;
--建立子類檢視
create or replace view  deptno_avg_sal_a as
       select e.deptno dt,avg(e.sal) avg_sal from emp e group by deptno;
select *  from deptno_avg_sal_a;
--求部門薪水的等級
select t.dt dl,s.grade gr from deptno_avg_sal_a t join salgrade s on
       t.avg_sal between losal and hisal;
--建立子類檢視
create or replace view dept_grade_a as
       select t.dt dl,s.grade gr from deptno_avg_sal_a t join salgrade s on
              t.avg_sal between losal and hisal;
select * from dept_grade_a;
--求出最低等級
select  min(gr) from dept_grade_a;
--求出部門名字
select d.dname from dept_grade_a de join dept d on de.dl = d.deptno
       where de.gr = (select min(gr) from dept_grade_a);
select * from dept;
--刪除檢視
drop view dept_grade_a;
drop view deptno_avg_sal_a;
drop view v_emp_dept_b;
----------------------------------------------------------------------
--建立表
create table temp as 
       select *from emp where 1=2;
----where 1=2 建立的是空表單
select * from temp;
create table temp2 as 
       select *from emp where 1=1;
select * from temp2;
----where 1=1 建立的是全部資料的表單
--插入資料
insert into temp select * from emp;
--刪除表單
drop table temp;
drop table temp2;

---------------------------------------------------------------------
--number(x,y) : 數字型別,最長x x位,y y位小數
--varchar2(maxlength) : 變長字串,這個引數的上限是32767位元組。
--                     宣告方式如下 varchar2(L L),L L 為字串長度,
--                     沒有預設值,作為變數最大32767個位元組
--char(max_length) : 定長字串 ,最大2000個位元組
--date : 日期型別(只能精確到秒)
--timestamp : 時間戳(精確到微秒)
--long : 長字串,最大 2GB

--瞭解型別
--clob : 最大長度4G -->大物件很少使用:如果存在大物件,一般的解決方案
--                     存入檔案地址(地址為程式所在應用伺服器的相對路徑)
--blob : 存二進位制檔案

--主鍵約束是資料庫中最重要的一種約束。在關係中,主鍵值不可為空,也不
--允許出現重複,即關係要滿足實體完整性規則。
--主鍵從功能上看相當於非空且唯一
--一個表中只允許一個主鍵
--主鍵是表中能夠唯一確定一個行資料的欄位
--主鍵欄位可以是單欄位或者多欄位的組合
--oracle為主鍵建立對應的唯一性索引。

-------------------------------------------------------------------
--procedural language和sql的結合體。通過增加變數、控制語句,使我們可以寫
--           一些邏輯更復雜的資料庫操作。

--匿名塊由一下四部分組成:
--declare    (可選)
--宣告各種變數或遊標的地方
--begin      (必要)
--開始執行語句
--       單行註釋用兩個連在一起的‘-’表示。
         /*多行註釋語句,可以換行*/
--exception     (可選)
--出錯後的處理
--end;          (必要)(請注意end後面的分號)


--1.變數必須在 declare 語句塊中宣告
--   變數宣告的語法規則
--identifier [constant] datatype [not null] [:=| default expr];
--如:
--變數名  型別 := 初始值;
-- v_str varchar2(10) := 'abc';

--2.變數的命名規則
--變數名不能夠使用保留字,如from、select等
--變數名最多包含30個字元
--不要與資料庫的表或者列同名
--每一行只能宣告一個變數
--建議:
--a).普通變數 v_
--b).常量 c_
--3.賦值語句:
--a).PL/SQL中的賦值使用  :=
--b)."=" 被用作比較操作符
--c).賦值語句中有一些規則需要遵守
--     字元型別必須使用單引號
--     不可以使用group by
--     可以使用數學操作符或字串連線操作符

--常用變數型別:
--普通變數
--  %type
--  %rowtype
--  varray
--  table
--  record
--變數宣告規則
--  變數名不能夠使用保留字,如from、select等
--  第一個字元必須是字母
--  變數名最多包含30個字元
--  不要與資料庫的表或者列同名
--  每行只能宣告一個變數
--  普通變數的型別主要有:
--    binary_integer : 整數,主要用來計數而不是用來表示欄位型別
--    number(x,y) : 數字型別,最長x位,y位小數
--    varchar2(maxlength)  : 變長字串,這個引數的上限是32767位元組
--                         宣告方式如下 varchar2(L),L為字串長度,
--                         沒有預設值,作為變數最大32767個位元組
--char(max_length) : 定長字串
--date : 日期
--boolean  : 布林型別,可以取值為 true、false和null值


--table 義記錄表(或索引表) 資料型別
--先宣告table型別(宣告具體的table型別)
--type table 型別的名稱 is table of data_type [index by binary_integer];


--1.單選擇語句:
--   if 條件  then
--   end if;
--2.雙重選擇:
--   if 條件 then
--   else
--   end if;
--3.多選擇:
--   if 條件 then
--   elsif 條件 then
--   elsif 條件 then
--   else
--   end if;


--1.do-while 迴圈,先執行後判斷:
--   loop
--   exit when 條件
--   end loop;
--2.while 迴圈,先判斷後執行:
--   while 條件 loop
--   end loop;
--3.for 迴圈,能夠確定次數,不用宣告變數,增長變數
--   for index in[reverse] min..max loop
--   end loop;
--  index 不能手動改變值,內部自動維護 +1 或 -1

------------------------------------------------------------------
--cursor 分類:
--                           |--顯式 cursor
--           --靜態 cursor --|
--          |                |--隱式 cursor
--cursor  --|
--          |                             |-- 強型別(限制),規定返回型別
--          |--動態 cursor --ref cursor --|
--                                        |-- 弱型別(非限制),不規定返回型別
--                                                 --可以獲取任何結果集

--隱式遊標:
--  可以使用名字sql來訪問,但要注意,通過sql遊標總是隻能訪問前一個處理
--  操作或單行select操作的遊標屬性。所以通常在剛剛執行完操作之後,立即
--  使用sql遊標來操作屬性。遊標的屬性有4種。分別是:
--  sql %isopen,sql %found,sql %notfound,sql %rowcount

--sql%isopen 返回的型別是布林型,判斷遊標是否被開啟,如果開啟 %ispen 等於
--           true,否則等於false,即執行過程中為真,結束後為假。

--sql%notfound 返回值為布林型,判斷遊標所在的行是否有效,如果有效,則
--             %found 等於true,否則等於false,即與%found 屬性返回值相反。

--sql%found 返回值的型別為布林值,值為true代表插入、刪除、更新或單行查詢
--          操作成功。

--sql%rowcount 返回值型別為整形,返回當前位置為止遊標讀取的記錄行數,即成功
--             執行的資料行數。


------------------------------------------------------------------------
--顯式遊標:
--    主要是用於對查詢語句的處理,尤其是在查詢結果為多條記錄的情況下;
--隱式遊標:
--    而對於非查詢語句,如修改、刪除操作,則由oracle系統自動地為這些操作設定
--    操作設定遊標並建立其工作區,這些由系統隱含建立的遊標稱為:隱式遊標。
--    隱式遊標的名字為sql,這是由 oracle 系統定義的。對於隱式遊標的操作,如
--    定義、開啟、取值及關閉操作,都由 oracle 系統自動地完成,無需使用者進行
--    處理。使用者只要通過隱式遊標的相關屬性,來完成相應的操作。在隱式遊標的
--    工作區中,所存放的資料是與使用者自定義的遊標無關的、最新處理的一條sql
--    語句所包含的資料。
--    格式呼叫為:sql%
--    注: insert,update,delete,select 語句中不必明確定義遊標。

--1.遊標:cursor
--   遊標就是指在某個結果集上的指標,通過這個指標的移動,我們得以遍歷整個結果集
--2.遊標的使用步驟(標準)
--   1).宣告遊標
--   2).開啟遊標
--   3).處理遊標中的資料
--   4).關閉遊標

--ref 遊標:動態遊標
--   1).在執行時使不同的語句與之關聯
--   2).ref遊標可以使用遊標變數
--屬性引用型別的一種 ,在執行時動態 的改變遊標的指向。for迴圈中不能使用
--ref遊標,因為for自動開啟遊標
--   1).弱型別遊標:
--       沒有返回型別的遊標變數,有動態關聯sql字串
--       type refempcur is ref cursor;
--   2).強型別遊標
--       有返回型別的遊標變數,不能關聯sql字串,只能關聯sql命令
--       type refempcur is ref cursor return emp%rowtype; 
---      遊標僅能開啟emp表的資料。
--       open 遊標名: for select_statement

------------------------------------------------------------------
--建立儲存過程
create [or replace] procedure procedure_name
([arg1 [in | out | in out]] type1 [default value1],[arg2 [in | out | in out]] type2 [default value2],--.....
[argn [in | out | in out]] typen [default valuen])
[authid definer | current_user]
{is | as}
--<宣告部分>
begin
--<執行部分>
exception
--<可選的異常錯誤處理程式>
end;

----------------------------------------------------------------------
--觸發器
--  觸發器是資料庫發生某個操作時自動執行的一類的程式
--  用於保持資料的完整性或記錄資料庫操作資訊方面
--  觸發器不能夠被直接呼叫,只能夠在某些事件發生時觸發,也就是系統自動呼叫
--觸發器的構建語法:
--  create [or replace] trigger trigger_name
--  before | after
--  event1 [or event2 or event3 ....]
--  on table_name [for each row]
--  begin
--  statement;
--  ...
--  end;

--event通常是 insert 、delete 或 update 等DML操作

--觸發器分為語句級觸發器和行級觸發器
--語句級觸發器是指每執行一條DML語句,該觸發器就執行一次
--行級觸發器是指每個DML操作影響幾條記錄,就會觸發幾次 (for each row)
--行級觸發器中由於涉及到了每條記錄的資料變動,所以對於每條記錄的資料來說
--就有新值和舊值之分。
--用關鍵字 :new 和 :old 來代表新的記錄和舊的記錄。

--jdbc 呼叫 儲存過程:
public class Test{
     public  static void main(String[] args){
          try{
              Class.forName("oracle.jdbc.driver.OracleDriver");
              String url = "jdbc:oracle:thin:@localhost:1521:orcl";
              Connection conn = DriverManager.getConnection(url,"scott","tiger");
              System.out.println(conn.isClosed());
              CallableStatement cs = conn.prepareCall("{call delRepeat(?,?,?)}");
              cs.setString(1,"emp");
              cs.setString(2,"ename");
              cs.registerOutParameter(3,OracleTypes.NUMBER);
              cs.executeQuery();
              System.out.println(cs.getObject(3));
              conn.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
     }
}

-----------------------------------------------------------------------------
--外傳:

--case when 方法
--decode 方法

--為所有人漲工資,標準是:10部門漲10%;20%部門漲15%;30部門漲20%;
--其他部門漲18%。
select * from emp;
select ename,(case deptno when 10 then sal*1.1
       when 20 then sal*1.15 
         when 30 then sal*1.2 
           else sal*1.18 end) v_sal
             from emp e;
--等價於下面的:
select ename,decode(deptno,10,sal*1.1,20,sal*1.15,30,sal*1.2,sal*1.18) v_sal
       from emp e;

------------------------------------------------------------------
------------------------------------------------------------------
select * from emp e where sal in (800,2000,3000,5000);
select * from emp e where ename in ('KING','JONES','FORD','MARTIN');
select *from emp e where sal between 1200 and 4000;
select * from emp e where e.deptno not in (20);
select * from emp e where e.deptno != 20;
select *  from emp e where (e.deptno = 10 or e.deptno = 30)
       and e.sal > 1500;
select * from emp e where e.deptno in (10,30) and e.sal >1500;
select * from emp e where e.hiredate > to_date('1981-02-05','yyyy-mm-dd');

-----------------------------------------------------------------------
--1、查詢部門編號為10的員工資訊
select * from emp  where deptno = 10;
--2、查詢年薪大於3萬的人員的姓名與部門編號
select * from emp e where (e.sal+nvl(comm,0))*12 > 30000;
--3、查詢佣金為null的人員姓名與工資
select * from emp e where comm is null;
--4、查詢工資大於1500 且 and 含有佣金的人員姓名
select * from emp e where e.sal > 1500 and  comm is not null;
--5、查詢工資大於1500 或 or含有佣金的人員姓名
select * from emp e where e.sal > 1500 or comm is not null;
--6、查詢姓名裡面含有 S 員工資訊 工資、名稱
select * from emp e where e.ename like '%S%';
--7、求姓名以J開頭第二個字元O的員工姓名的與工資
select * from emp e where e.ename like 'JO%';
--8、求包含%的僱員姓名
select * from emp e where e.ename like '%A%%' escape 'A';
--9、使用in查詢部門名稱為 SALES 和 RESEARCH 的僱員姓名、工資、部門編號
--   用 distinct去重
select * from emp;
select distinct e.ename,e.deptno from emp e,dept d
       where d.dname in ('SALES','RESEARCH') and e.deptno = d.deptno;
--10、使用exists查詢部門名稱為SALES和RESEARCH 的僱員姓名、工資、部門編號。
--    exists是判斷exits後面的sql語句是否為真,若為真則整個sql句子成立,--    否則沒有任何記錄。語法如下:
--  ** select * from a where exists (select g from b where a.id = b.id);
select distinct e.ename,e.deptno from  emp e 
       where exists (select * from emp e,dept d  
             where d.dname in ('SALES','RESEARCH') and d.deptno = e.deptno);
---------------------------------------------------------------------
select * from emp e order by e.sal desc,e.ename asc;
select e.ename || ' is a ' || e.job from emp e; 
---------------------------------------------------------------------
--1、使用基本查詢語句.
--(1)查詢DEPT表顯示所有部門名稱.
select d.dname from dept d;
--(2)查詢EMP表顯示所有僱員名及其全年收入(月收入=工資+補助),--處理NULL行,並指定列別名
--為"年收入"。(NVL(comm,0) comm取空值時用0替代)
select e.ename,(e.sal+nvl(comm,0))*12 sal_all from emp e;
--(3)查詢顯示不存在僱員的所有部門號。
select d.deptno from dept d 
       where d.deptno not in (select distinct e.deptno from emp e 
             where d.deptno = e.deptno);

--2、限制查詢資料
--(1)查詢EMP表顯示工資超過2850的僱員姓名和工資。
select e.ename,e.sal from emp e where e.sal >2850;
--(2)查詢EMP表顯示工資不在1500~2850之間的所有僱員及工資。
select e.ename,e.sal from emp e where e.sal not in (1500,2850);
--(3)查詢EMP表顯示程式碼為7566的僱員姓名及所在部門程式碼。
select e.ename,e.deptno from emp e where e.empno = 7566;
--(4)查詢EMP表顯示部門10和30中工資超過1500的僱員名及工資。
select e.ename,e.sal from  emp e where e.deptno in (10,30) and e.sal >1500;
--(5)查詢EMP表顯示第2個字元為"A"的所有僱員名其工資。
select e.ename,e.sal from emp e where e.ename like '_A%';
--(6)查詢EMP表顯示補助非空的所有僱員名及其補助。
select e.ename,e.comm from emp e where comm is not null;
--3、排序資料
--(1)查詢EMP表顯示所有僱員名、工資、僱傭日期,並以僱員名的升序進行排序。
select e.ename,e.hiredate from emp e order by e.ename asc;
--(2)查詢EMP表顯示在1981年2月1日到1981年5月1日之間僱傭的僱員名、
--     崗位及僱傭日期,並以僱傭日期進行排序。
select e.ename,e.job,e.hiredate from emp e 
       where e.hiredate >= to_date('1981-02-01','yyyy-mm-dd') and
             e.hiredate <= to_date('1981-05-01','yyyy-mm-dd') 
             order by e.hiredate desc;
--或
select e.ename,'yyyy-mm-dd') 
             order by e.hiredate asc;
--(3)查詢EMP表顯示獲得補助的所有僱員名、工資及補助,並以工資升序和
--補助降序排序。
select e.ename,e.comm from emp e 
       where (e.comm is not null and e.comm != 0) order by e.sal,e.comm desc;

-----------------------------------------------------------------------------
select lower(ename) from emp e ;
select upper(lower(ename)) from emp
select substrb('流aa川abc',4) from dual;
select ename,substr(ename,2) from emp e;
select ename,length(ename) from emp 
select ename,lpad(ename,'6','*') from emp;
select ename,rpad(ename,instr(ename,'A') from emp;
select ename,ename) from emp;
select ename,replace(ename,'A','-') from emp;
select rtrim('xxgao lao shixxx','x') text from dual;
select trim(both 'x' from 'xxxgao lao shixxx') from dual;


select ceil(19.2) from dual;
select floor(19.2) from dual;
select mod(19,2) from dual;
select trunc(23.653) from dual;
select trunc(23.653,2) from dual;
select trunc(23.653,-1) from  dual;
select round(23.653) from dual;
select round(23.653,2) from dual;
select round(23.653,-1) from dual;


select sysdate from dual;
select current_date from dual;
select add_months(sysdate,3) from dual;
select months_between(sysdate,add_months(sysdate,3)) from dual;
select sysdate-2 from dual;
select sysdate+2 from dual;
select ename,round((sysdate-hiredate)/7) weeks from emp e where e.deptno = 10;
select * from emp where empno = to_number('7369');
select * from emp e where hiredate = '20-2月-1981';
select * from emp e where hiredate = to_date('1981-02-20','yyyy-mm-dd');
select '199'-90 from dual;

select to_char(sysdate,'yyyy-mm-dd hh24 : mi : ss') from dual;
select ename,hiredate,to_char(hiredate,'yyyy-mm-dd hh24:mi:ss') from emp;

select to_char(sal,'$99,999.9999') salary from emp where ename = 'ALLEN';
select to_char(sal,'$00,000.0000') salary from emp where ename = 'ALLEN';
select to_char(sal,'L00,000.0000') salary from emp where ename = 'ALLEN';

select to_date('04,05,19,23,40','yy,mm,dd,hh24,mi,ss') from dual;
select to_date('2004-09-19','yyyy-mm-dd') from dual;

select to_number('$39343.783','$99990.000') from dual;
select to_number('11.231','999.999') from dual;

select e.*,nvl(to_char(mgr),'boss') mgr from emp e where mgr is null;

select to_char(next_day(add_months(hiredate,6),'星期五'),'yyyy-mm-dd') dat
       from emp e order by hiredate;

---------------------------------------------------------------------
--1、查詢82年員工
select * from emp e where to_char(e.hiredate,'yy') like '82';
--2、查詢36年工齡的人員
select * from emp e where (sysdate - to_date(hiredate))/365 > 36;
--3、顯示員工僱傭期 6 個月後下一個星期一的日期
select e.ename,to_char(next_day(add_months(hiredate,'星期一'),'yyyy-mm-dd') from emp e order by hiredate asc;
--4、找沒有上級的員工,把mgr的欄位資訊輸出為 "boss"
select ename,'boss') from emp e where mgr is null;
--5、為所有人長工資,標準是:10部門長10%;20部門長15%;30
--部門長20%其他部門長18%
--case when 方法:
select e.ename,(case deptno when 10 then e.sal*1.1 when 20 then e.sal*1.15 
       when 30 then e.sal*1.2 else e.sal*1.18  end) v_sal 
         from emp e;
--decode 方法: 
select e.ename,e.sal*1.1,e.sal*1.15,e.sal*1.2,e.sal*1.18) v_sal from emp e;

----------------------------------------------------------------
select sum(e.sal),avg(e.sal),min(sal),max(e.sal) from emp e;
select min(hiredate),max(hiredate) from emp e;
select count(1) from emp e ;
select count(*) from emp e ;
select count(comm) from emp ;
select count(mgr) from emp;
select count(distinct deptno) from emp;

select avg(nvl(comm,0)) from emp e ;

select deptno,avg(sal) from emp group by deptno;
select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000;

--• 求部門下僱員的平均工資>2000 人數
select deptno,count(1) from emp group by deptno 
       having deptno in (select deptno from emp e 
       group by deptno having avg(sal) > 2000);
--部門薪水最高
select deptno,max(sal) max_sal from emp e group by deptno;

select max(e.max_sal) from (select max(sal) max_sal from 
       emp e group by deptno) e

select max(sal),deptno,job from emp group by deptno,job;

select avg(sal) from emp where sal > 1200
       group by deptno having avg(sal) > 1500
       order by avg(sal) asc;
-- 部門裡面 工齡最小和最大的人找出來       
--找出部門裡面最大和最小工齡 
select deptno,max(hiredate) min_date,min(hiredate) max_date
       from emp e group by deptno;
--找出工齡對應的名字 
select e.deptno,e.ename eename,e.hiredate from emp e join
       (select deptno dt,min(hiredate) max_date 
       from emp e group by deptno) t on (e.hiredate = t.min_date or 
       e.hiredate = t.max_date) and e.deptno = t.dt order by e.deptno;

---------------------------------------------------------------------
--1、查詢10號部門中編號最新入職的員工,工齡最長的員工的個人資訊。
select e.* from emp e join 
       (select deptno dt,min(hiredate) max_date 
        from emp e group by deptno) t on (e.hiredate = t.min_date or
        e.hiredate = t.max_date) and e.deptno = 10;
--2、從“software”找到‘f’的位置,用‘*’左或右填充到15位,去除其中的‘a’。
--–Instr()字串出現的位置,instr( string ,’A‘)
--–lpad,rpad 填充字元型資料
--–ltrim/rtrim (string1,string2)
select instr('software','f'),lpad('software',15,'*'),rpad('software',replace('software','a','') from dual;
--3、查詢員工的獎金,如果獎金不為NULL顯示‘有獎金’,為null則顯示無獎金
select e.ename,nvl2(comm,'有獎金','無獎金') from emp e;
select e.ename,decode(comm,null,'無獎金','有獎金') from emp e;
--4、寫一個查詢顯示當前日期,列標題顯示為Date。再顯示六個月後的日期,
--下一個星期日的日期,該月最後一天的日期。
select sysdate dat,next_day(sysdate,'星期日'),last_day(sysdate) from dual;
--5、查詢EMP表按管理者編號升序排列,如果管理者編號為空則把為空的在最前顯
--示
select * from emp order by mgr nulls first;
--6、求部門平均薪水
select deptno,avg(sal) from emp e group by deptno;
--7、按部門求出工資大於1300人員的 部門編號、平均工資、最小佣金、
--最大佣金,並且最大佣金大於100
select deptno,avg(sal),min(comm),max(comm) from emp e 
       where sal > 1500 group by deptno having max(comm)>100;
--8、找出每個部門的平均、最小、最大薪水
select deptno,max(sal) from emp e group by deptno;
--9、查詢出僱員名,僱員所在部門名稱, 工資等級
select e.ename,d.deptno,s.grade from emp e,dept d,salgrade s
       where sal between losal and hisal and e.deptno = d.deptno;

select * from emp,salgrade where sal between losal and hisal;

select e.empno,d.loc from emp e,dept d 
       where e.deptno = d.deptno and e.ename like 'JAMES';

select e.empno,d.dname,d.loc,d.deptno from emp e,dept d
       where e.deptno = d.deptno and e.deptno = 10;

select * from emp e,salgrade s where sal between losal and hisal;

select e.ename,e.deptno,dept d 
       where e.deptno = d.deptno(+);

select e.ename,dept d
       where e.deptno(+) = d.deptno;

-----------------------------------------------------------------
--99語法
select e.empno,dept d
       where e.deptno = d.deptno;

select e.empno,d.loc from emp e
       cross join dept d where e.deptno = d.deptno;

select * from emp e natural join dept d where deptno = 10;

select e.empno,d.loc from emp e join dept d
       using(deptno) where deptno = 10;

select e.ename,s.grade from emp e join dept d on 
       e.deptno = d.deptno
       join salgrade s on e.sal between losal and hisal;

select * from emp e right outer join dept d on e.deptno = d.deptno;

select * from emp e left outer join dept d on e.deptno = d.deptno;

select * from emp e right join dept d on e.deptno = d.deptno;

select * from emp e inner join dept d on e.deptno = d.deptno;

select * from emp e join dept d on e.deptno = d.deptno;

select * from emp e join dept d using(deptno);

--查詢那些薪水在整個僱員平均薪水之上的人
select * from emp e where (e.sal+nvl(comm,0)) > (select 
       avg(sal+nvl(comm,0)) from emp);
--找出所有的經理人
select distinct e.ename from emp e,emp em where e.empno = em.mgr;
select *from emp e where empno in (select distinct mgr from emp);
--找出部門20最高收入的職員
select e.ename,e.comm from emp e join (select deptno,max(sal+nvl(comm,0)) max_sal from emp group by deptno) em 
       on e.deptno = 20 and e.sal = em.max_sal;
select e.ename,e.comm from emp e 
       where (e.sal+nvl(comm,0)) >= all(select (sal+nvl(comm,0))
       from emp where deptno =20) and deptno = 20;
--求每個部門平均薪水的平均水平
--求部門平均薪水
select deptno dt,avg(sal) avg_sal from emp e group by e.deptno;
--求等級
select t.dt,t.avg_sal,s.grade from (select deptno dt,avg(sal) avg_sal
       from emp e group by e.deptno) t join salgrade s on t.avg_sal between 
       losal and hisal;
       
---------------------------------------------------------------------
--1、求平均薪水最高的部門的部門編號
--求部門的平均薪水
select deptno,avg(sal+nvl(comm,0)) from emp group by deptno ;
--求出最大值
select  max(max_avg) from (select deptno dt,0)) max_avg
       from emp group by deptno) t 
--求出部門編號
select k.dt,k.sal_avg from 
       (select e.deptno dt,0)) sal_avg from emp e 
          group by deptno) k where k.sal_avg = (select  max(max_avg) from 
          (select deptno dt,0)) max_avg
                  from emp group by deptno) t )
--2、求部門平均薪水的等級
select k.dt,k.avg_sal,s.grade from (select e.deptno dt,avg(sal) avg_sal 
       from emp e group by deptno) k join salgrade s on k.avg_sal 
       between losal and hisal;
--3、求部門平均的薪水等級
--求部門的薪水等級
select e.deptno dt,e.sal sl,s.grade gd from emp e join salgrade s on e.sal 
       between losal and hisal;
--求平均值
select k.dt,avg(k.sl),avg(k.gd) from (select e.deptno dt,s.grade gd from emp e join salgrade s on e.sal 
       between losal and hisal) k group by k.dt;
--4、求薪水最高的前5名僱員
--先排列薪水
select * from emp e order by e.sal desc;
--擷取前五名 
select t.*,rownum rm from (select * from emp e order by e.sal desc) t
       where rownum <= 5;
--5、求薪水最高的第6到10名僱員
select k.* from (select t.*,rownum rm from (select * from emp e order by 
       e.sal desc) t where rownum <= 10) k where k.rm >= 6;

---------------------------------------------------------------------
---------------------------------------------------------------------
declare
    type tb_mytable is table of dept.deptno%type index by
         binary_integer;
    v_tb_mytable tb_mytable;
begin
    dbms_output.put_line('hello world');
end;

--do while 迴圈:
declare
    v_num number(3,0) := 0;
begin
    loop
      dbms_output.put_line(v_num);
      v_num := v_num + 2;
      exit when v_num = 100;
    end loop;
end;

--while 迴圈
declare
    v_num number(3,0) := 0;
begin
    while v_num != 100 loop
      dbms_output.put_line(v_num);
      v_num := v_num + 2;
    end loop;
end;

--while迴圈:
declare
    type t is table of number(3) index by varchar2(3);
    hash_t t;
    l_row varchar2(3);
begin
    hash_t('a') := 10;
    hash_t('b') := 20;
    l_row := hash_t.first;
    while(l_row is not null) loop
    dbms_output.put_line(hash_t(l_row));
    l_row := hash_t.next(l_row);
    end loop;
end;

--for迴圈:
declare
    type t is table of number(3) index by pls_integer;
    hash_t t;
    l_row varchar2(3);
begin
    hash_t(1) := 10;
    hash_t(2) := 20;
    for i in hash_t.first..hash_t.last loop
      dbms_output.put_line(hash_t(i));
      end loop;
end;

--if條件句:
declare
    i integer;
    b01 boolean := true;
begin
    if b01 then
      dbms_output.put_line('test');
      end if;
end;


declare
    v_name varchar2(20);
begin
    select ename into v_name from emp e where
           e.deptno = 20 and e.empno = &empno;
     dbms_output.put_line(v_name);
exception
     when others then
       dbms_output.put_line('資料未找到');
       rollback;
end;

select * from emp;

declare
    v_empno emp.empno%type := &empno;
    v_comm emp.comm%type;    
begin
    select comm into v_comm from emp e where e.empno = v_empno;
    if(v_comm is null) then
        dbms_output.put_line('無獎金');
    else
        dbms_output.put_line('有獎金');
    end if;
exception
    when others then
      dbms_output.put_line(sqlcode||'-----'||sqlerrm);
    rollback;
end;

declare
    v_empno emp.empno%type := &empno;
    v_comm emp.comm%type;
begin
    select comm into v_comm from emp e where e.empno = v_empno;
    if(v_comm is null) then
        dbms_output.put_line('無獎金');
    elsif(v_comm > 0 and v_comm < 800) then
        dbms_output.put_line('獎金少的可憐');
    else
        dbms_output.put_line('獎金可觀');
    end if;
exception
    when others then
      dbms_output.put_line(sqlcode||'----'||sqlerrm);
    rollback;
end;

-----------------------------------------------------------
-------------------------------------------------------------
--建立表
create  table v_temp02(
    vno number(2),vname varchar2(20),vage number(3)
);
--增
insert into v_temp02 values(10,'王哥',18);
insert into v_temp02 values(11,'楊哥',19);
insert into v_temp02 values(12,'張哥',17);
insert into v_temp02 values(13,'黃哥',20);
insert into v_temp02 values(14,'文哥',21);
--commit提交事務,可加可不加,加了之後,就直接提交,而沒機會回滾了
commit;
--查
select * from v_temp02;
--修改資料
begin
   update v_temp02 set vname = '忠哥',vage = 18 where vno = 12;
   if sql%found then
      dbms_output.put_line('更新了'||sql%rowcount||'記錄');
   end if;
   commit;
   if not sql%isopen then
     dbms_output.put_line('自動關閉遊標');
   end if;
end;
--刪除資料
delete from v_temp02 where vno = 11;
commit;
--刪除表
drop table v_temp02;

-----------------------------------------------------------------
--遊標
--如抓取一條資料
declare
   cursor my_cursor is select * from dept; --宣告遊標(定義的遊標不能有into句子)
   v_dept dept%rowtype;       --定義變數
begin
   open my_cursor;            --開啟遊標
   fetch my_cursor into v_dept;      --使用遊標
   dbms_output.put_line(v_dept.deptno||'----'||v_dept.dname||
         '---'||v_dept.loc);
   close my_cursor;                  --關閉遊標
end;

--loop迴圈(do-while)遍歷遊標,利用loop迴圈和%notfound屬性實現遊標遍歷
declare
   cursor my_cursor is select * from dept;   --宣告遊標
   v_dept dept%rowtype;       --定義變數
begin
   open my_cursor;            --開啟遊標
   loop                       --開啟loop(do-while)迴圈
      fetch my_cursor into v_dept;   --使用遊標
      exit when my_cursor%notfound;  --定義遊標停止條件
      dbms_output.put_line(v_dept.deptno||'---'||
           v_dept.dname||'---'||v_dept.loc);
   end loop;                  --關閉loop迴圈
   close my_cursor;           --關閉遊標
exception                     --一次
   when others then
     dbms_output.put_line(sqlcode||'---'||sqlerrm);
   rollback;
end;

--while迴圈遍歷遊標,利用while迴圈配合%found屬性實現遊標遍歷。
declare
   cursor my_cursor is select * from dept;   --宣告遊標
   v_dept my_cursor%rowtype;         --定義變數
begin
   open my_cursor;                   --開啟遊標
   fetch my_cursor into v_dept;      --使用遊標
   while my_cursor%found loop        --開啟while迴圈
      dbms_output.put_line(v_dept.deptno||'---'||
             v_dept.dname||'---'||v_dept.loc);
      fetch my_cursor into v_dept;   --使用遊標
   end loop;                         --關閉迴圈
   close my_cursor;                  --關閉遊標
exception                            --異常
   when others then
     dbms_output.put_line(sqlcode||'---'||sqlerrm);
   rollback;                         --回滾
end;

--for迴圈遍歷遊標,利用for迴圈遍歷遊標,不需要開啟遊標,也不需要關閉遊標
--甚至不用宣告迴圈變數,不用抓取,最簡單。推薦使用
declare
    cursor my_cursor is select * from dept;
    v_dept dept%rowtype;
begin
    for v_dept in my_cursor loop
       dbms_output.put_line(v_dept.deptno||'---'||v_dept.dname||
               '---'||v_dept.loc);
    end loop;
exception
    when others then
       dbms_output.put_line(sqlcode||'---'||sqlerrm);
    rollback;
end;

-------------------------------------------------------------------
--使用遊標,更新狀態資料,如果年薪 < 5000 低 [5000,8000] 中 >= 8000 高
--複製表
create table copy_emp02 as select * from emp where 1=1;

select * from copy_emp02;

--加入狀態列
alter table copy_emp02 add status varchar2(20);

--帶引數的遊標
declare
    cursor my_cursor(v_no dept.deptno%type) is 
           select * from dept d where deptno = v_no;
    v_dept dept%rowtype;
begin
    for v_dept in my_cursor(&v_no) loop
      dbms_output.put_line('第'||my_cursor%rowcount||'行,資料為:'||
               v_dept.deptno||'---'||v_dept.dname||'---'||v_dept.loc);
    end loop;
end;

--引數01
declare
    cursor my_cursor(v_sal number) is select * from emp e 
           where e.sal > v_sal;
    v_emp emp%rowtype;
begin
    for v_emp in my_cursor(1500) loop        --sal大於1500的僱員
      dbms_output.put_line(v_emp.ename||'---'||v_emp.sal);
    end loop;
end;

--引數02
declare
    cursor my_cursor(v_sal number default 2000) is select * from emp e
           where e.sal > v_sal;   --預設值為2000,即sal > 2000的僱員
    v_emp emp%rowtype;
begin
    for v_emp in my_cursor(v_sal => 1500) loop
      dbms_output.put_line(v_emp.ename||'---'||v_emp.sal);
    end loop;
exception
    when others then
      dbms_output.put_line(sqlcode||'---'||sqlerrm);
    rollback;
end;

--引數03
declare
    cursor my_cursor(v_sal number default 2000) is select * from emp e
           where e.sal > v_sal;         --預設值為2000,即sal > 2000的僱員
    v_emp emp%rowtype;      
begin
    for v_emp in my_cursor loop         --帶預設值的引數 ,可不加括號和引數
      dbms_output.put_line(v_emp.ename||'---'||v_emp.sal);
    end loop;
end;

-------------------------------------------------------------------
--宣告遊標,有引數有返回值
select * from emp where deptno = 10;
declare
   type emp_record is record(
      v_ename emp.ename%type,v_hiredate emp.hiredate%type
   );
   v_record emp_record;
   cursor my_cursor(v_deptno number,v_job varchar2) return emp_record
          is select ename,hiredate from emp where deptno = v_deptno 
          and job = v_job;
   v_emp emp%rowtype;
begin
   open my_cursor(10,'CLERK');
   loop
      fetch my_cursor into v_record;
      if my_cursor%found then
         dbms_output.put_line(v_record.v_ename||'的僱傭日期是'||v_record.v_hiredate);
      else
         dbms_output.put_line('已經處理結束了');
      exit;
      end if;
    end loop;
    close my_cursor;
exception
    when others then
    dbms_output.put_line(sqlcode||'---'||sqlerrm);
    rollback;
end;

--基於遊標定義記錄變數,比宣告記錄型別變數要方便
declare
    cursor my_cursor(v_deptno number,v_job varchar2) is select ename,hiredate from emp e where e.deptno = v_deptno and e.job = v_job;
    v_cursor my_cursor%rowtype;
    v_emp emp%rowtype;
begin
    open my_cursor(10,'CLERK');
    loop
       fetch my_cursor into v_cursor;
       if my_cursor%found then
          dbms_output.put_line(v_cursor.ename||'的僱傭日期是'||v_cursor.hiredate);
       else
          dbms_output.put_line('已經處理完畢');
          exit;
       end if;
    end loop;
    close my_cursor;
end;

--更新或刪除
create table emp2 as select * from emp ;      --建立新版,不影響舊錶
select * from emp2;

--在這個例子中,我們同個select語句後面新增 for update
--來提示oracle鎖定記錄以便進行更新,然後用 where current of
--來指明操作時新增在當前遊標所指向的記錄上

declare
    cursor my_cursor is select * from emp2 for update;
    v_temp my_cursor%rowtype;
begin
    for v_emp in my_cursor loop
       if (v_emp.sal < 2000) then
          update emp2 set sal = sal * 2 where current of my_cursor;
       elsif(v_emp.sal = 1500) then
          delete from emp2 where current of my_cursor;
       end if;
    end loop;
    commit;
end;

--刪除表emp2
drop table emp2;

-------------------------------------------------------------------
--動態遊標:弱型別遊標
declare
    type RefEmpCur is ref cursor;
    mycur RefEmpCur;
    v_emp emp%rowtype;
begin
    open mycur for select * from emp;
    loop
       fetch mycur into v_emp;
       exit when mycur%notfound;
       dbms_output.put_line(v_emp.deptno||'---'||v_emp.ename||'---'||
                 v_emp.sal);
    end loop;
    close mycur;
end;

--多語句
declare
    type RefEmpCur is ref cursor;
    mycur RefEmpCur;
    v_emp emp%rowtype;
    v_dept dept%rowtype;
begin
    open mycur for select * from emp;
    loop
       fetch mycur into v_emp;
       exit when mycur%notfound;
       dbms_output.put_line(v_emp.deptno||'---'||v_emp.ename||'---'||
                 v_emp.sal);
    end loop;
    close mycur;
    open mycur for select * from dept;
    loop
        fetch mycur into v_dept;
        exit when mycur%notfound;
        dbms_output.put_line(v_dept.deptno||'---'||v_dept.dname||'---'||
                  v_dept.loc);
    end loop;
    close mycur;
end;

--sys_refcursor
declare
    --type ref_cursor is ref cursor;
    --cur01 ref_cursor;
    cur01 sys_refcursor;
    v_emp emp%rowtype;
    v_sql  varchar2(100);
begin
    v_sql := 'select * from emp';
    open cur01 for v_sql;
    loop
       fetch cur01 into v_emp;
       exit when (cur01%notfound);
       dbms_output.put_line(v_emp.ename);
    end loop;
    close cur01;
end;

-------------------------------------------------------------------
select * from student_score;
--建立儲存過程

-------------------------------------------------------------------
--實現一個函式判斷資料是時間格式型別
create or replace function isDate(in_date in varchar2) return number 
       is v_result number(2);
       v_date date;
begin
    v_date := to_date(in_date,'yyyy-mm-dd');
    v_result := case when v_date is not null then 1 else 0 end;
    return v_result;
exception
    when others then
       dbms_output.put_line(sqlcode||'---'||sqlerrm);
    rollback;
end;

select isDate('1982-02-10') from dual;

--trigger 觸發器例子
create
    or replace trigger trig_temp after update on dept for each row
begin
    update emp set deptno =: new.deptno where deptno =: old.deptno;
end;

--如果沒有觸發器,是不能直接更新的
update dept set deptno = 90 where deptno = 30

select * from dept;




 

 

 

 

                

 

 

 

返回主目錄