oracle ql/sql 相關語法解析

這篇文章主要介紹了Oracle中游標Cursor基本用法詳解,仍是比較全面的,具備必定參考價值,須要的朋友能夠了解下。
 

查詢html

  SELECT語句用於從數據庫中查詢數據,當在PL/SQL中使用SELECT語句時,要與INTO子句一塊兒使用,查詢的
返回值被賦予INTO子句中的變量,變量的聲明是在DELCARE中。SELECT INTO語法以下:sql

  SELECT [DISTICT|ALL]{*|column[,column,...]}
  INTO (variable[,variable,...] |record)
  FROM {table|(sub-query)}[alias]
  WHERE............

  PL/SQL中SELECT語句只返回一行數據。若是超過一行數據,那麼就要使用顯式遊標(對遊標的討論咱們將
在後面進行),INTO子句中要有與SELECT子句中相同列數量的變量。INTO子句中也能夠是記錄變量。數據庫

%TYPE屬性安全

  在PL/SQL中能夠將變量和常量聲明爲內建或用戶定義的數據類型,以引用一個列名,同時繼承他的數據類
型和大小。這種動態賦值方法是很是有用的,好比變量引用的列的數據類型和大小改變了,若是使用了%TYPE,
那麼用戶就沒必要修改代碼,不然就必須修改代碼。cors

例:函數

  v_empno SCOTT.EMP.EMPNO%TYPE;
  v_salary EMP.SALARY%TYPE;

  不但列名可使用%TYPE,並且變量、遊標、記錄,或聲明的常量均可以使用%TYPE。這對於定義相同數據類
型的變量很是有用。oop

  DELCARE
   V_A NUMBER(5):=10;
  V_B V_A%TYPE:=15;
  V_C V_A%TYPE;
  BEGIN
  DBMS_OUTPUT.PUT_LINE
  ('V_A='||V_A||'V_B='||V_B||'V_C='||V_C);
  END
  SQL>/
  V_A=10 V_B=15 V_C=
  PL/SQL procedure successfully completed.
  SQL>

其餘DML語句測試

其它操做數據的DML語句是:INSERT、UPDATE、DELETE和LOCK TABLE,這些語句在PL/SQL中的語法與在SQL中
的語法相同。咱們在前面已經討fetch

論過DML語句的使用這裏就再也不重複了。在DML語句中可使用任何在DECLARE部分聲明的變量,若是是嵌套
塊,那麼要注意變量的做用範圍。spa

例:

 1 CREATE OR REPLACE PROCEDURE FIRE_EMPLOYEE (pempno in number)
 2   AS
 3   v_ename EMP.ENAME%TYPE;
 4   BEGIN
 5   SELECT ename INTO v_ename
 6   FROM emp
 7   WHERE empno=p_empno;
 8   INSERT INTO FORMER_EMP(EMPNO,ENAME)
 9   VALUES (p_empno,v_ename);
10   DELETE FROM emp
11   WHERE empno=p_empno;
12   UPDATE former_emp
13   SET date_deleted=SYSDATE
14   WHERE empno=p_empno;
15   EXCEPTION
16   WHEN NO_DATA_FOUND THEN
17   DBMS_OUTPUT.PUT_LINE('Employee Number Not Found!');
18   END

  DML語句的結果

當執行一條DML語句後,DML語句的結果保存在四個遊標屬性中,這些屬性用於控制程序流程或者瞭解程序
的狀態。當運行DML語句時,PL/SQL打開一個內建遊標並處理結果,遊標是維護查詢結果的內存中的一個區域,
遊標在運行DML語句時打開,完成後關閉。隱式遊標只使用SQL%FOUND,

SQL%NOTFOUND,SQL%ROWCOUNT三個屬性.SQL%FOUND,SQL%NOTFOUND是布爾值,SQL%ROWCOUNT是整數值。

SQL%FOUND和SQL%NOTFOUND

在執行任何DML語句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在執行DML語句後,SQL%FOUND的屬性值將是:

  . TRUE :INSERT
  . TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
  . TRUE :SELECT INTO至少返回一行

當SQL%FOUND爲TRUE時,SQL%NOTFOUND爲FALSE。

SQL%ROWCOUNT

在執行任何DML語句以前,SQL%ROWCOUNT的值都是NULL,對於SELECT INTO語句,若是執行成功
,SQL%ROWCOUNT的值爲1,若是沒有成功,SQL%ROWCOUNT的值爲0,同時產生一個異常NO_DATA_FOUND.

SQL%ISOPEN

SQL%ISOPEN是一個布爾值,若是遊標打開,則爲TRUE, 若是遊標關閉,則爲FALSE.對於隱式遊標而言SQL%
ISOPEN老是FALSE,這是由於隱式遊

標在DML語句執行時打開,結束時就當即關閉。

事務控制語句

事務是一個工做的邏輯單元能夠包括一個或多個DML語句,事物控制幫助用戶保證數據的一致性。若是事務控制邏輯單元中的任何一個DML
語句失敗,那麼整個事務都將回滾,在PL/SQL中用戶能夠明確地使用COMMIT、ROLLBACK、SAVEPOINT以及
SET TRANSACTION語句。

COMMIT語句終止事務,永久保存數據庫的變化,同時釋放全部LOCK,ROLLBACK終止現行事務釋放全部LOCK,
但不保存數據庫的任何變化,SAVEPOI

NT用於設置中間點,當事務調用過多的數據庫操做時,中間點是很是有用的,SET TRANSACTION用於設置事
務屬性,好比read-write和隔離級等。

顯式遊標

查詢返回結果超過一行時,就須要一個顯式遊標,此時用戶不能使用select into語句。PL/SQL管理隱式
遊標,當查詢開始時隱式遊標打開,查詢結束時隱式遊標自動關閉。顯式遊標在PL/SQL塊的聲明部分聲明,在執行部分或異常處理部分打開,取數據,關閉。

使用遊標

這裏要作一個聲明,咱們所說的遊標一般是指顯式遊標,所以從如今起沒有特別指明的狀況,咱們所說的
遊標都是指顯式遊標。要在程序中使用遊標,必須首先聲明遊標。

聲明遊標

語法:

CURSOR cursor_name IS select_statement;

在PL/SQL中游標名是一個未聲明變量,不能給遊標名賦值或用於表達式中。

例:

  
DELCARE
  CURSOR C_EMP IS SELECT empno,ename,salary
  FROM emp
  WHERE salary>2000
  ORDER BY ename;
  ........
  BEGIN

 

  在遊標定義中SELECT語句中不必定非要表能夠是視圖,也能夠從多個表或視圖中選擇的列,甚至可使用*
來選擇全部的列 。

打開遊標

使用遊標中的值以前應該首先打開遊標,打開遊標初始化查詢處理。打開遊標的語法是:

  OPEN cursor_name

 cursor_name是在聲明部分定義的遊標名。

例:

OPEN C_EMP;

  關閉遊標

語法:

 CLOSE cursor_name

例:

CLOSE C_EMP;

從遊標提取數據

從遊標獲得一行數據使用FETCH命令。每一次提取數據後,遊標都指向結果集的下一行。語法以下:

FETCH cursor_name INTO variable[,variable,...]

對於SELECT定義的遊標的每一列,FETCH變量列表都應該有一個變量與之相對應,變量的類型也要相同。

例:

 1 SET SERVERIUTPUT ON
 2   DECLARE
 3   v_ename EMP.ENAME%TYPE;
 4   v_salary EMP.SALARY%TYPE;
 5   CURSOR c_emp IS SELECT ename,salary FROM emp;
 6   BEGIN
 7   OPEN c_emp;
 8   FETCH c_emp INTO v_ename,v_salary;
 9 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
10   FETCH c_emp INTO v_ename,v_salary;
11   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
12   FETCH c_emp INTO v_ename,v_salary;
13   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
14   CLOSE c_emp;
15   END

這段代碼無疑是很是麻煩的,若是有多行返回結果,可使用循環並用遊標屬性爲結束循環的條件,以這
種方式提取數據,程序的可讀性和簡潔性都大爲提升,下面咱們使用循環從新寫上面的程序: 

 1 SET SERVERIUTPUT ON
 2   DECLARE
 3   v_ename EMP.ENAME%TYPE;
 4   v_salary EMP.SALARY%TYPE;
 5   CURSOR c_emp IS SELECT ename,salary FROM emp;
 6   BEGIN
 7   OPEN c_emp;
 8   LOOP
 9   FETCH c_emp INTO v_ename,v_salary;
10   EXIT WHEN c_emp%NOTFOUND;
11   DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
12   END

  記錄變量

定義一個記錄變量使用TYPE命令和%ROWTYPE,關於%ROWsTYPE的更多信息請參閱相關資料。

記錄變量用於從遊標中提取數據行,當遊標選擇不少列的時候,那麼使用記錄比爲每列聲明一個變量要方
便得多。

當在表上使用%ROWTYPE並將從遊標中取出的值放入記錄中時,若是要選擇表中全部列,那麼在SELECT子句
中使用*比將全部列名列出來要安全得多。

例:

 1 SET SERVERIUTPUT ON
 2   DECLARE
 3   R_emp EMP%ROWTYPE;
 4   CURSOR c_emp IS SELECT * FROM emp;
 5   BEGIN
 6   OPEN c_emp;
 7   LOOP
 8   FETCH c_emp INTO r_emp;
 9   EXIT WHEN c_emp%NOTFOUND;
10   DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
11   END LOOP;
12   CLOSE c_emp;
13   END;

%ROWTYPE也能夠用遊標名來定義,這樣的話就必需要首先聲明遊標:

SET SERVERIUTPUT ON
  DECLARE
  CURSOR c_emp IS SELECT ename,salary FROM emp;
  R_emp c_emp%ROWTYPE;
  BEGIN
  OPEN c_emp;
  LOOP
  FETCH c_emp INTO r_emp;
  EXIT WHEN c_emp%NOTFOUND;
  DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
  END LOOP;
  CLOSE c_emp;
  END;

帶參數的遊標

與存儲過程和函數類似,能夠將參數傳遞給遊標並在查詢中使用。這對於處理在某種條件下打開遊標的情
況很是有用。它的語法以下:

CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;

定義參數的語法以下:

Parameter_name [IN] data_type[{:=|DEFAULT} value]

與存儲過程不一樣的是,遊標只能接受傳遞的值,而不能返回值。參數只定義數據類型,沒有大小。

另外能夠給參數設定一個缺省值,當沒有參數值傳遞給遊標時,就使用缺省值。遊標中定義的參數只是一個佔位符,在別處引用該參數不必定可靠。

在打開遊標時給參數賦值,語法以下:

OPEN cursor_name[value[,value]....];

參數值能夠是文字或變量。

例:

 1 DECALRE
 2   CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno;
 3   CURSOR c_emp (p_dept VARACHAR2) IS
 4   SELECT ename,salary
 5   FROM emp
 6   WHERE deptno=p_dept
 7   ORDER BY ename
 8   r_dept DEPT%ROWTYPE;
 9   v_ename EMP.ENAME%TYPE;
10   v_salary EMP.SALARY%TYPE;
11   v_tot_salary EMP.SALARY%TYPE;
12   BEGIN
13   OPEN c_dept;
14   LOOP
15   FETCH c_dept INTO r_dept;
16   EXIT WHEN c_dept%NOTFOUND;
17   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
18   v_tot_salary:=0;
19   OPEN c_emp(r_dept.deptno);
20   LOOP
21   FETCH c_emp INTO v_ename,v_salary;
22   EXIT WHEN c_emp%NOTFOUND;
23   DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
24   v_tot_salary:=v_tot_salary+v_salary;
25   END LOOP;
26   CLOSE c_emp;
27   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
28   END LOOP;
29   CLOSE c_dept;
30   END;

  遊標FOR循環

在大多數時候咱們在設計程序的時候都遵循下面的步驟:

一、打開遊標
二、開始循環
三、從遊標中取值
四、檢查那一行被返回
五、處理
六、關閉循環
七、關閉遊標

能夠簡單的把這一類代碼稱爲遊標用於循環。但還有一種循環與這種類型不相同,這就是FOR循環,用於
FOR循環的遊標按照正常的聲明方式聲明,它的優勢在於不須要顯式的打開、關閉、取數據,測試數據的存在、定義存放數據的變量等等。

遊標FOR循環的語法以下:

  FOR record_name IN
  (corsor_name[(parameter[,parameter]...)]
  | (query_difinition)
  LOOP
  statements
  END LOOP;

  下面咱們用for循環重寫上面的例子:

 1 DECALRE
 2   CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno;
 3   CURSOR c_emp (p_dept VARACHAR2) IS
 4   SELECT ename,salary
 5   FROM emp
 6   WHERE deptno=p_dept
 7   ORDER BY ename
 8   v_tot_salary EMP.SALARY%TYPE;
 9 BEGIN
10   FOR r_dept IN c_dept LOOP
11   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
12   v_tot_salary:=0;
13   FOR r_emp IN c_emp(r_dept.deptno) LOOP
14   DBMS_OUTPUT.PUT_LINE('Name:' || v_ename || 'salary:' || v_salary);
15   v_tot_salary:=v_tot_salary+v_salary;
16   END LOOP;
17   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
18   END LOOP;
19   END;

  在遊標FOR循環中使用查詢

在遊標FOR循環中能夠定義查詢,因爲沒有顯式聲明因此遊標沒有名字,記錄名經過遊標查詢來定義。

 1  DECALRE
 2   v_tot_salary EMP.SALARY%TYPE;
 3   BEGIN
 4   FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP
 5   DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
 6   v_tot_salary:=0;
 7   FOR r_emp IN (SELECT ename,salary
 8   FROM emp
 9   WHERE deptno=p_dept
10   ORDER BY ename) LOOP
11   DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
12   v_tot_salary:=v_tot_salary+v_salary;
13   END LOOP;
14   DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
15   END LOOP;
16   END;

  遊標中的子查詢

  語法以下:

  CURSOR C1 IS SELECT * FROM emp
  WHERE deptno NOT IN (SELECT deptno
  FROM dept
  WHERE dname!='ACCOUNTING');

  能夠看出與SQL中的子查詢沒有什麼區別。

  遊標中的更新和刪除

  在PL/SQL中依然可使用UPDATE和DELETE語句更新或刪除數據行。顯式遊標只有在須要得到多行數據的情
況下使用。PL/SQL提供了僅僅使  用遊標就能夠執行刪除或更新記錄的方法。
  UPDATE或DELETE語句中的WHERE CURRENT OF子串專門處理要執行UPDATE或DELETE操做的表中取出的最近的
數據。要使用這個方法,在聲明遊標  時必須使用FOR UPDATE子串,當對話使用FOR UPDATE子串打開一個遊標時,全部返回集中的數據行都將處於行級(ROW-LEVEL)獨佔式鎖定,其
  他對象只能查詢這些數據行,不能進行UPDATE、DELETE或SELECT...FOR            UPDATE操做。

語法:

  FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
  [nowait]

  在多表查詢中,使用OF子句來鎖定特定的表,若是忽略了OF子句,那麼全部表中選擇的數據行都將被鎖定。
若是這些數據行已經被其餘會話鎖定,那麼正常狀況下ORACLE將等待,直到數據行解鎖。

  在UPDATE和DELETE中使用WHERE CURRENT OF子串的語法以下:

  WHERE{CURRENT OF cursor_name|search_condition}

  例:

 1 DELCARE
 2   CURSOR c1 IS SELECT empno,salary
 3   FROM emp
 4   WHERE comm IS NULL
 5   FOR UPDATE OF comm;
 6   v_comm NUMBER(10,2);
 7   BEGIN
 8   FOR r1 IN c1 LOOP
 9   IF r1.salary<500 THEN
10   v_comm:=r1.salary*0.25;
11   ELSEIF r1.salary<1000 THEN
12   v_comm:=r1.salary*0.20;
13   ELSEIF r1.salary<3000 THEN
14   v_comm:=r1.salary*0.15;
15   ELSE
16   v_comm:=r1.salary*0.12;
17   END IF;
18   UPDATE emp;
19   SET comm=v_comm
20   WHERE CURRENT OF c1l;
21   END LOOP;
22   END
 -聲明遊標
--宗地表的調查日期LANDINFO_RESEARCHDATE
--複製到流程表的權屬調查時間FLOW_REASEARCHTIME
 1 DECLARE 
 2 cursor cur_sel_all is select LANDINFO_RESEARCHDATE,LANDINFO_LANDNO from t_leoa_landinfo; --定義遊標
 3    l_date t_leoa_landinfo.landinfo_researchdate%type; --聲明變量分別保存t_leoa_landinfo的各列
 4    l_landNo t_leoa_landinfo.landinfo_landno%type; 
 5 begin
 6 open cur_sel_all;
 7   loop                 --循環取數,並將遊標數據填充到返回紀錄集合中
 8    fetch cur_sel_all into l_date,l_landNo;
 9    exit when cur_sel_all%NOTFOUND; --循環退出條件
10    if cur_sel_all%FOUND then --獲取數據 
11     update T_LEOA_BOOKFLOW t2 set FLOW_REASEARCHTIME = l_date where l_landNo = t2.landinfo_landno; 
12    end if;
13   end loop;
14 close cur_sel_all;
15 end;

下面再分享一下另一則遊標使用方法的代碼,具體以下:

 1 -- 聲明遊標;CURSOR cursor_name IS select_statement
 2 --For 循環遊標
 3 --(1)定義遊標
 4 --(2)定義遊標變量
 5 --(3)使用for循環來使用這個遊標
 6 declare
 7     --類型定義
 8     cursor c_job
 9     is
10     select empno,ename,job,sal
11     from emp
12     where job='MANAGER';
13     --定義一個遊標變量v_cinfo c_emp%ROWTYPE ,該類型爲遊標c_emp中的一行數據類型
14     c_row c_job%rowtype;
15 begin
16     for c_row in c_job loop
17      dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
18     end loop;
19 end;
20 --Fetch遊標
21 --使用的時候必需要明確的打開和關閉
22 declare 
23     --類型定義
24     cursor c_job
25     is
26     select empno,ename,job,sal
27     from emp
28     where job='MANAGER';
29     --定義一個遊標變量
30     c_row c_job%rowtype;
31 begin
32     open c_job;
33      loop
34       --提取一行數據到c_row
35       fetch c_job into c_row;
36       --判讀是否提取到值,沒取到值就退出
37       --取到值c_job%notfound 是false 
38       --取不到值c_job%notfound 是true
39       exit when c_job%notfound;
40       dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
41      end loop;
42     --關閉遊標
43    close c_job;
44 end;

 

 1 --1:任意執行一個update操做,用隱式遊標sql的屬性%found,%notfound,%rowcount,%isopen觀察update語句的執行狀況。
 2     begin
 3      update emp set ENAME='ALEARK' WHERE EMPNO=7469;
 4      if sql%isopen then
 5       dbms_output.put_line('Openging');
 6       else
 7        dbms_output.put_line('closing');
 8        end if;
 9      if sql%found then
10       dbms_output.put_line('遊標指向了有效行');--判斷遊標是否指向有效行
11       else
12        dbms_output.put_line('Sorry');
13        end if;
14        if sql%notfound then
15         dbms_output.put_line('Also Sorry');
16         else
17          dbms_output.put_line('Haha');
18          end if;
19           dbms_output.put_line(sql%rowcount);
20           exception 
21            when no_data_found then
22             dbms_output.put_line('Sorry No data');
23             when too_many_rows then
24              dbms_output.put_line('Too Many rows');
25              end;
26 declare
27     empNumber emp.EMPNO%TYPE;
28     empName emp.ENAME%TYPE;
29     begin
30      if sql%isopen then
31       dbms_output.put_line('Cursor is opinging');
32       else
33        dbms_output.put_line('Cursor is Close');
34        end if;
35        if sql%notfound then
36         dbms_output.put_line('No Value');
37         else
38          dbms_output.put_line(empNumber);
39          end if;
40          dbms_output.put_line(sql%rowcount);
41          dbms_output.put_line('-------------');
42          select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499;
43          dbms_output.put_line(sql%rowcount);
44         if sql%isopen then
45         dbms_output.put_line('Cursor is opinging');
46         else
47         dbms_output.put_line('Cursor is Closing');
48         end if;
49          if sql%notfound then
50          dbms_output.put_line('No Value');
51          else
52          dbms_output.put_line(empNumber);
53          end if;
54          exception 
55           when no_data_found then
56            dbms_output.put_line('No Value');
57            when too_many_rows then
58             dbms_output.put_line('too many rows');
59             end;

 

--2,使用遊標和loop循環來顯示全部部門的名稱
--遊標聲明
declare 
    cursor csr_dept
    is
    --select語句
    select DNAME
    from Depth;
    --指定行指針,這句話應該是指定和csr_dept行類型相同的變量
    row_dept csr_dept%rowtype;
begin
    --for循環
    for row_dept in csr_dept loop
      dbms_output.put_line('部門名稱:'||row_dept.DNAME);
    end loop;
end;

 

 1 --3,使用遊標和while循環來顯示全部部門的的地理位置(用%found屬性)
 2 declare
 3     --遊標聲明
 4     cursor csr_TestWhile
 5     is
 6     --select語句
 7     select LOC
 8     from Depth;
 9     --指定行指針
10     row_loc csr_TestWhile%rowtype;
11 begin
12  --打開遊標
13     open csr_TestWhile;
14     --給第一行喂數據
15     fetch csr_TestWhile into row_loc;
16     --測試是否有數據,並執行循環
17      while csr_TestWhile%found loop
18       dbms_output.put_line('部門地點:'||row_loc.LOC);
19       --給下一行喂數據
20       fetch csr_TestWhile into row_loc;
21      end loop;
22     close csr_TestWhile;
23 end; 
24 select * from emp

 

  1 --4,接收用戶輸入的部門編號,用for循環和遊標,打印出此部門的全部僱員的全部信息(使用循環遊標)
  2 --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
  3 --定義參數的語法以下:Parameter_name [IN] data_type[{:=|DEFAULT} value] 
  4 declare 
  5    CURSOR 
  6    c_dept(p_deptNo number)
  7    is
  8    select * from emp where emp.depno=p_deptNo;
  9    r_emp emp%rowtype;
 10 begin
 11     for r_emp in c_dept(20) loop
 12       dbms_output.put_line('員工號:'||r_emp.EMPNO||'員工名:'||r_emp.ENAME||'工資:'||r_emp.SAL);
 13     end loop;
 14 end;
 15 select * from emp  
 16 --5:向遊標傳遞一個工種,顯示此工種的全部僱員的全部信息(使用參數遊標)
 17 declare 
 18     cursor
 19     c_job(p_job nvarchar2)
 20     is 
 21     select * from emp where JOB=p_job;
 22     r_job emp%rowtype;
 23 begin 
 24     for r_job in c_job('CLERK') loop
 25       dbms_output.put_line('員工號'||r_job.EMPNO||' '||'員工姓名'||r_job.ENAME);
 26     end loop;
 27 end;
 28 SELECT * FROM EMP
 29 --6:用更新遊標來爲僱員加佣金:(用if實現,建立一個與emp表一摸同樣的emp1表,對emp1表進行修改操做),並將更新先後的數據輸出出來 
 30 --http://zheng12tian.iteye.com/blog/815770 
 31     create table emp1 as select * from emp;
 32 declare
 33     cursor
 34     csr_Update
 35     is
 36     select * from emp1 for update OF SAL;
 37     empInfo csr_Update%rowtype;
 38     saleInfo emp1.SAL%TYPE;
 39 begin
 40   FOR empInfo IN csr_Update LOOP
 41    IF empInfo.SAL<1500 THEN
 42     saleInfo:=empInfo.SAL*1.2;
 43     elsif empInfo.SAL<2000 THEN
 44     saleInfo:=empInfo.SAL*1.5;
 45     elsif empInfo.SAL<3000 THEN
 46     saleInfo:=empInfo.SAL*2;
 47    END IF;
 48    UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;
 49    END LOOP;
 50 END;
 51 --7:編寫一個PL/SQL程序塊,對名字以‘A'或‘S'開始的全部僱員按他們的基本薪水(sal)的10%給他們加薪(對emp1表進行修改操做)
 52 declare 
 53    cursor
 54    csr_AddSal
 55    is
 56    select * from emp1 where ENAME LIKE 'A%' OR ENAME LIKE 'S%' for update OF SAL;
 57    r_AddSal csr_AddSal%rowtype;
 58    saleInfo emp1.SAL%TYPE;
 59 begin
 60    for r_AddSal in csr_AddSal loop
 61      dbms_output.put_line(r_AddSal.ENAME||'原來的工資:'||r_AddSal.SAL);
 62      saleInfo:=r_AddSal.SAL*1.1;
 63      UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
 64    end loop;
 65 end;
 66 --8:編寫一個PL/SQL程序塊,對全部的salesman增長佣金(comm)500
 67 declare
 68    cursor
 69      csr_AddComm(p_job nvarchar2)
 70    is
 71      select * from emp1 where  JOB=p_job FOR UPDATE OF COMM;
 72    r_AddComm emp1%rowtype;
 73    commInfo emp1.comm%type;
 74 begin
 75   for r_AddComm in csr_AddComm('SALESMAN') LOOP
 76     commInfo:=r_AddComm.COMM+500;
 77      UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;
 78   END LOOP;
 79 END;
 80 --9:編寫一個PL/SQL程序塊,以提高2個資格最老的職員爲MANAGER(工做時間越長,資格越老)
 81 --(提示:能夠定義一個變量做爲計數器控制遊標只提取兩條數據;也能夠在聲明遊標的時候把僱員中資格最老的兩我的查出來放到遊標中。)
 82 declare
 83   cursor crs_testComput
 84   is
 85   select * from emp1 order by HIREDATE asc;
 86   --計數器
 87   top_two number:=2;
 88   r_testComput crs_testComput%rowtype;
 89 begin
 90   open crs_testComput;
 91     FETCH crs_testComput INTO r_testComput;
 92      while top_two>0 loop
 93        dbms_output.put_line('員工姓名:'||r_testComput.ENAME||' 工做時間:'||r_testComput.HIREDATE);
 94        --計速器減一
 95        top_two:=top_two-1;
 96        FETCH crs_testComput INTO r_testComput;
 97       end loop;
 98    close crs_testComput;
 99 end;
100 --10:編寫一個PL/SQL程序塊,對全部僱員按他們的基本薪水(sal)的20%爲他們加薪,
101 --若是增長的薪水大於300就取消加薪(對emp1表進行修改操做,並將更新先後的數據輸出出來) 
102 declare
103   cursor
104     crs_UpadateSal
105   is
106     select * from emp1 for update of SAL;
107     r_UpdateSal crs_UpadateSal%rowtype;
108     salAdd emp1.sal%type;
109     salInfo emp1.sal%type;
110 begin
111     for r_UpdateSal in crs_UpadateSal loop
112       salAdd:= r_UpdateSal.SAL*0.2;
113       if salAdd>300 then
114        salInfo:=r_UpdateSal.SAL;
115        dbms_output.put_line(r_UpdateSal.ENAME||': 加薪失敗。'||'薪水維持在:'||r_UpdateSal.SAL);
116        else 
117        salInfo:=r_UpdateSal.SAL+salAdd;
118        dbms_output.put_line(r_UpdateSal.ENAME||': 加薪成功.'||'薪水變爲:'||salInfo);
119       end if;
120       update emp1 set SAL=salInfo where current of crs_UpadateSal;
121     end loop;
122 end;
123 --11:將每位員工工做了多少年零多少月零多少天輸出出來  
124 --近似
125  --CEIL(n)函數:取大於等於數值n的最小整數
126  --FLOOR(n)函數:取小於等於數值n的最大整數
127  --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml
128 declare
129  cursor
130   crs_WorkDay
131   is
132   select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,
133     trunc(mod(months_between(sysdate, hiredate), 12)) AS months,
134     trunc(mod(mod(sysdate - hiredate, 365), 12)) as days
135   from emp1;
136  r_WorkDay crs_WorkDay%rowtype;
137 begin
138   for  r_WorkDay in crs_WorkDay loop
139   dbms_output.put_line(r_WorkDay.ENAME||'已經工做了'||r_WorkDay.SPANDYEARS||'年,零'||r_WorkDay.months||'月,零'||r_WorkDay.days||'');
140   end loop;
141 end;
142 --12:輸入部門編號,按照下列加薪比例執行(用CASE實現,建立一個emp1表,修改emp1表的數據),並將更新先後的數據輸出出來
143 -- deptno raise(%)
144 -- 10   5%
145 -- 20   10%
146 -- 30   15%
147 -- 40   20%
148 -- 加薪比例以現有的sal爲標準
149 --CASE expr WHEN comparison_expr THEN return_expr
150 --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END
151 declare
152    cursor
153      crs_caseTest
154      is
155      select * from emp1 for update of SAL;
156      r_caseTest crs_caseTest%rowtype;
157      salInfo emp1.sal%type;
158    begin
159      for r_caseTest in crs_caseTest loop
160      case 
161       when r_caseTest.DEPNO=10
162       THEN salInfo:=r_caseTest.SAL*1.05;
163       when r_caseTest.DEPNO=20
164       THEN salInfo:=r_caseTest.SAL*1.1;
165       when r_caseTest.DEPNO=30
166       THEN salInfo:=r_caseTest.SAL*1.15;
167       when r_caseTest.DEPNO=40
168       THEN salInfo:=r_caseTest.SAL*1.2;
169      end case;
170      update emp1 set SAL=salInfo where current of crs_caseTest;
171     end loop;
172 end;
173 --13:對每位員工的薪水進行判斷,若是該員工薪水高於其所在部門的平均薪水,則將其薪水減50元,輸出更新先後的薪水,員工姓名,所在部門編號。
174 --AVG([distinct|all] expr) over (analytic_clause)
175 ---做用:
176 --按照analytic_clause中的規則求分組平均值。
177  --分析函數語法:
178  --FUNCTION_NAME(<argument>,<argument>...)
179  --OVER
180  --(<Partition-Clause><Order-by-Clause><Windowing Clause>)
181    --PARTITION子句
182    --按照表達式分區(就是分組),若是省略了分區子句,則所有的結果集被看做是一個單一的組
183    select * from emp1
184 DECLARE
185    CURSOR 
186    crs_testAvg
187    IS
188    select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG
189    FROM EMP1 for update of SAL;
190    r_testAvg crs_testAvg%rowtype;
191    salInfo emp1.sal%type;
192    begin
193    for r_testAvg in crs_testAvg loop
194    if r_testAvg.SAL>r_testAvg.DEP_AVG then
195    salInfo:=r_testAvg.SAL-50;
196    end if;
197    update emp1 set SAL=salInfo where current of crs_testAvg;
198    end loop;
199 end;
相關文章
相關標籤/搜索