查詢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;