?? script_77.txt
字號:
---------- emp_data.txt ----------
/*
* 范例名稱:數據準備
* 文件名稱:emp_data.txt
*/
--目前使用scott中的emp,dept數據.不用重建emp
---------- implicursor.txt ----------
/*
* 范例名稱:隱式cursor(Implicit Cursor)
* 文件名稱:implicursor.txt
*/
--Implicit Cursor TEST.USE %FOUND,%ROWCOUNT,%NOTFOUND
begin
update sm_emp
set name = '張飛2' ,
salary = 99 where empid = '0000000009';
--使用隱式光標,判斷是否更新成功。
if SQL%NOTFOUND then
--如果還沒有相應id的紀錄,insert.
dbms_output.put_line('sorry .沒有雇員 0000000009 .insert');
insert into sm_emp values ('0000000009','張飛',99,null);
end if;
end;
--test
SELECT * FROM sm_emp;
connect scott/tiger
---------- cursor_loop.txt ----------
/*
* 范例名稱:Cursor and Loop
* 文件名稱:cursor_loop.txt
*/
--test cursor for loop
DECLARE
CURSOR c_emp IS
SELECT ename,sal
FROM emp
ORDER BY ename;
--定義游標
v_tot_sal NUMBER (10,2);
BEGIN
v_tot_sal :=0;
--游標for循環,求出雇員的工資總數。
FOR r_emp IN c_emp LOOP
DBMS_OUTPUT.PUT_LINE ('Name:' || r_emp.ename ||'salary:' || r_emp.sal);
v_tot_sal :=v_tot_sal +r_emp.sal;
END LOOP;
DBMS_OUTPUT.PUT_LINE
('Total salary is'||v_tot_sal);
END;
--test cursor for loop:光標不必顯式打開,以上block沒有cursor 的open語句。
--test: record在for loop外不可以引用
DECLARE
CURSOR c_emp IS
SELECT ename,sal
FROM emp
ORDER BY ename;
v_tot_sal NUMBER (10,2);
BEGIN
v_tot_sal :=0;
FOR r_emp IN c_emp LOOP
DBMS_OUTPUT.PUT_LINE ('Name:' || r_emp.ename ||'salary:' || r_emp.sal);
v_tot_sal :=v_tot_sal +r_emp.sal;
END LOOP;
DBMS_OUTPUT.PUT_LINE
('last person is ' || r_emp.ename );
END;
--err!在for以外引用record.
---------- lock.txt ----------
/*
* 范例名稱:鎖
* 文件名稱:lock.txt
*/
--創建實驗表1
--第一個SQL*Plus窗口:sqlplus(1)
create table a(a number);
insert into a values(1);
insert into a values(2);
commit;
--lock1:數據庫設置lock的原因
--sqlplus(1)
update a set a=10 where a=2;
--沒有commit;
--新打開一個SQL*Plus窗口
--(第二個sqlplus(2))
select * from a;
--可以看到a=2的紀錄
update a set a=11 where a=2;
commit;
--此時結果如何呢?sqlplus(1)還未commit,
--如果允許sqlplus(2)更新并commit則sqlplus(1)的用戶會發現他剛更改的紀錄不見了。
--因此數據庫設置lock
--lock2:
--sqlplus(1)
select * from a for update;
--(第二個SQL*Plus(2))
update a set a=111 where a=1;
--lock住。因為a=10這條紀錄在sqlplus(1) select * from a for update;鎖定范圍內。
-此時,系統停頓狀態,等待解鎖,
-只要在第一個窗口發出roll;或commit;命令,即可解除鎖定狀態。
--第一個SQL*Plus窗口
--只鎖定部分紀錄
select * from a where a =1 for update;
--(第二個SQL*Plus)
update a set a=9 where a=10;
--ok.因為a=10不在鎖定結果集內。
update a set a=12 where a=1;
--另一個sqlplus
update a set a=10;
-此時,系統停頓狀態,等待解鎖。因為,企圖更改a =1 的紀錄
-只要在第一個窗口發出roll;或commit;命令,即可解除鎖定狀態。
--原因是dml并發更改相同數據
--Lock3:行獨占鎖
--sqlplus(1)
create table a(a number);
insert into a values(1);
insert into a values(2);
commit;
update a set a=10 where a=2;
--沒有commit;
--新打開一個SQL*Plus窗口
--(第二個sqlplus(2))
select * from a;
--可以看到a=2的紀錄
update a set a=11 where a=1;
commit;
--此時結果如何呢?sqlplus(1)還未commit.
update ok.因為,a=1不在sqlplus(1)更新語句作用之內。
---------- exception.txt ----------
/*
* 范例名稱:Exceptions:PL/SQL的錯誤處理機制
* 文件名稱:exception.txt
*/
--exception的處理機質:出現exception直接跳到exception處理段。
set serveroutput on
DECLARE
num_a NUMBER := 6;
num_b NUMBER;
BEGIN
num_b := 12;
--num_b := 0;
num_a := num_a / num_b;
num_b := 7;
--正常執行數出結果
dbms_output.put_line(' Value of num_a ' || num_a);
dbms_output.put_line(' Value of num_b ' || num_b);
EXCEPTION
WHEN ZERO_DIVIDE
--當發生.../0時,執行如下代碼
/*......*/
THEN
dbms_output.put_line('Trying to divide by zero');
dbms_output.put_line(' Value of num_a ' || num_a);
dbms_output.put_line(' Value of num_b ' || num_b);
END;
--賦值錯誤EXCEPTION
DECLARE
X NUMBER:=10;
BEGIN
X:= 'yyyy'; --Error Here
EXCEPTION WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION HANDED');
--輸出日志 sysdate,user ,frompc......
--insert into a values('value_err EXCEPTION HANDED');
--insert into a values(x);
--get_name('0000000001');
END;
--------------------exception使用日志------------------
create table sm_log
(sm_user varchar2(10) not null,
s_date date not null,
err_msg varchar2(100) );
DECLARE
X NUMBER:=10;
BEGIN
X:= 'yyyy'; --Error Here
EXCEPTION WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION HANDED');
--輸出日志
insert into sm_log values
(user,sysdate,'value_err EXCEPTION HANDED');
--get_name('0000000001');
END;
select sm_user,to_char(s_date,'yyyy/mm/dd HH24:mi:ss'),err_msg from sm_log;
---------- named_exception.txt ----------
/*
* 范例名稱:預定義EXCEPTION
* 文件名稱:named_exception.txt
*/
--先建立SM_EMP:CreateTable_sm_emp.txt
DELETE FROM sm_emp WHERE name='TOM';
SET SERVEROUTPUT ON
--named exception test
DECLARE
v_name VARCHAR2(10);
n_sal NUMBER(8,2);
BEGIN
SELECT name , salary INTO v_name , n_sal FROM sm_emp
WHERE name='TOM';
DBMS_OUTPUT.PUT_LINE('TOM : SALARY :' || n_sal);
EXCEPTION
--注意:當多個exception在exception段中出現,只執行一個,之后直接跳到end。
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO EMPLOYEE NAMED TOM');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('TOO MANY TOM');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR!');
END;
--insert TOM
INSERT INTO sm_emp VALUES ('001','TOM',999.99,'62543678');
--再次運行named exception test block
--insert TOM again
INSERT INTO sm_emp VALUES ('002','TOM',999.99,'62543678');
--第三次運行named exception test block
---------- user_defined.txt ----------
/*
* 范例名稱:自定義異常處理
* 文件名稱:user_defined.txt
*/
INSERT INTO sm_emp VALUES ('003','TOM3',999.99,NULL);
--用戶定義的exception
DECLARE
CURSOR c_emp IS SELECT * FROM sm_emp;
loseTelno EXCEPTION;
BEGIN
--OPEN c_emp;
FOR r_emp IN c_emp LOOP
--當出現telno IS NULL,自定義例外。
IF r_emp.telno IS NULL THEN
RAISE loseTelno; --AN EMPLOYEE WITHOUT TELNO
END IF;
END LOOP;
EXCEPTION
WHEN loseTelno THEN
DBMS_OUTPUT.PUT_LINE('loseTelno Error!' || r_emp.name || 'is lost');
END;
--Error:PLS-00201: 必須說明標識符 'R_EMP.NAME':為什么?
--記住:cursor for loop 使用的record只在cursor for loop 內有效。
--改進
DECLARE
CURSOR c_emp IS SELECT * FROM sm_emp;
loseTelno EXCEPTION;
v_name varchar(10);
BEGIN
FOR r_emp IN c_emp LOOP
IF r_emp.telno IS NULL THEN
v_name := r_emp.name;
RAISE loseTelno; --AN EMPLOYEE WITHOUT TELNO
END IF;
END LOOP;
EXCEPTION
WHEN loseTelno THEN
DBMS_OUTPUT.PUT_LINE('loseTelno Error!' || v_name || 'is lost');
END;
---------------------------------擴展內容-----------------------------
---------- cursor_dml.txt ----------
/*
* 范例名稱:Cursor and DML
* 文件名稱:cursor_dml.txt
*/
select job ,comm,sal from emp;
DECLARE
CURSOR c1 IS SELECT empno,sal
FROM emp
WHERE comm IS NULL
FOR UPDATE;
--要求對comm(傭金)為空的紀錄更新。
v_comm NUMBER(10,2);
BEGIN
--用了一個光標for循環,逐條更新紀錄
FOR r1 IN c1 LOOP
IF r1.sal <500 THEN
v_comm :=r1.sal *0.25;
ELSIF r1.sal <1000 THEN
v_comm :=r1.sal *0.20;
ELSIF r1.sal <3000 THEN
v_comm :=r1.sal *0.15;
ELSE
v_comm :=r1.sal *0.12;
END IF;
/*UPDATE USE WHERE CURRENT OF CLAUSE:
用WHERE CURRENT OF更新emp的對應紀錄*/
UPDATE emp
SET comm =v_comm
WHERE CURRENT OF c1;
--在comm列中填入對應工資的25%,20%,15%,12%
END LOOP;
END;
--驗證
select job ,comm,sal from emp
--nested_new.txt作為擴展內容-----------------
---------- nested_new.txt ----------
/*
* 范例名稱:Nested Blocks
* 文件名稱:nested_new.txt
*/
<<OUTER_BLOCK>>
DECLARE
A varchar2(20);
B NUMBER;
BEGIN
--A, B可以在OUTER_BLOCK塊中訪問
<<SUB_BLOCK>>
DECLARE
C NUMBER;
C1 VARCHAR2(40);
B varchar2(20) :='aaa';
--B再一次被定義 為varchar2(20)。
BEGIN
--C只可以在子塊中訪問
--A可以在此塊中訪問
C1 :=A;
--c :=B;--有這句正確嗎?
--引用外層block的B
C :=OUTER_BLOCK.B;
END SUB_BLOCK;
--C不可以在這里訪問
END OUTER_BLOCK;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -