一、匿名塊
1、使用returning ... INTO 儲存增刪改表資料時的一些列的值
(01)增加資料時儲存資料
DECLARE
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
INSERT INTO emp(empno,ename,JOB,sal,comm,deptno) VALUES(&no,'zhaoliu','deve',3000,500,10) RETURNING ename,sal INTO v_ename,v_sal;
dbms_output.put_line(v_ename || ','||v_sal);
end; ---開啟控制檯輸出開關
SET serveroutput ON; (02)修改資料時儲存資料
DECLARE
v_ename emp.ename%TYPE;
v_sal emp.sal%type;
BEGIN
UPDATE emp SET sal=sal+100 WHERE empno=&no RETURNING ename,sal INTO v_ename,v_sal;
dbms_output.put_line(v_ename || ','||v_sal);
END; (03)刪除資料時儲存資料
DECLARE
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
DELETE FROM emp WHERE empno=&no RETURNING ename,sal INTO v_ename,v_sal;
dbms_output.put_line(v_ename || ','||v_sal);
END; 二、分支結構
1、if
IF 條件 THEN 結果;
END IF; IF 條件 THEN 結果;
ELSE 結果;
END IF; IF 條件 THEN 結果;
elsif 條件 THEN 結果;
....
ELSE 結果;
END IF; ---查詢一個員工薪水,判斷員工薪水如果大於3000,輸出他是一個白領;如果工資小於等於3000大於1500,輸出他是一個藍領;其它情況輸出是一個灰領;
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE empno=&no;
IF v_sal>3000 THEN
dbms_output.put_line('白領');
elsif v_sal>1500 THEN
dbms_output.put_line('藍領');
ELSE dbms_output.put_line('灰領');
END IF;
END; 2、case:
格式一:
CASE WHEN 條件 THEN 結果;
WHEN 條件 THEN 結果;
...
ELSE 結果;
END CASE; 格式二:
CASE 條件表示式 WHEN 值1 THEN 結果1;
WHEN 值2 THEN 結果2;
....
ELSE 結果m;
END CASE; ---輸入一個成績,判斷該成績等級,如果在99~90之間,返回為A,如果在89~80之間,返回為B,如果在79~70之間,返回C,其它返回為D
DECLARE
v_score NUMBER(3);
v_flag VARCHAR2(1);
BEGIN
v_score:=&score;
CASE trunc(v_score/10) WHEN 9 THEN v_flag:='A';
WHEN 8 THEN v_flag:='B';
WHEN 7 THEN v_flag:='C';
ELSE v_flag:='D';
END CASE;
dbms_output.put_line(v_score || ',該 成績的等級為:' || v_flag);
END; 三、迴圈結構
1、直到型迴圈
loop
執行迴圈體;
exit WHEN 條件;
END loop; ---在控制檯輸出1~5
DECLARE
v_i NUMBER(1):=1;
BEGIN
loop
dbms_output.put_line(v_i);
v_i:=v_i+1;
exit WHEN v_i>5;
END loop;
end; 2、while:
while 條件
loop
執行迴圈體;
END loop; ---在控制檯輸出1~5
DECLARE
v_i NUMBER(1):=1;
BEGIN
while v_i<=5
loop
dbms_output.put_line(v_i);
v_i:=v_i+1;
END loop;
end; 3、fOR:
FOR 迴圈變數 IN 最小值..最大值
loop
執行迴圈體;
END loop; ---在控制檯輸出1~5
BEGIN
for v_i in 1..5
loop
dbms_output.put_line(v_i);
END loop;
end; 練習:
建立一張表,只包含一個欄位id
先在表中插入一條記錄5
然後將10—20之間的數插入兩遍 四、儲存過程
語法:
CREATE [OR REPLACE] PROCEDURE 儲存過程名(形參1 IN|out 資料型別,形參2 IN|out 資料型別...)
IS | AS
定義部分;
begin
執行部分;
exception
異常部分;
END; 呼叫過程:
exec 儲存過程名(實參...);
call 儲存過程名(實參...); ---如果呼叫的是無參儲存過程,過程名後面必須() 1、建立一個無參儲存過程
CREATE PROCEDURE pro_demo1
IS
BEGIN
INSERT INTO dept VALUES(50,'deve','nanjing');
end; exec pro_demo1;
call pro_demo1(); 2、建立一個輸入引數儲存過程
---根據輸入的員工工號和新的月薪修改資料庫中該 員工的薪水
CREATE OR REPLACE PROCEDURE pro_demo1(NO emp.empno%TYPE,newsal emp.sal%TYPE)
is
BEGIN
update emp set sal=newsal where empno=no;
end; 一個為僱員加薪的過程
CREATE OR REPLACE PROCEDURE pro_demo1(NO emp.empno%TYPE,addsal emp.sal%TYPE)
is
BEGIN
UPDATE emp SET sal=sal+addsal WHERE empno=NO;
end; CALL pro_demo1(7788,10000); SELECT * FROM emp; 3、建立一個即有輸入引數也有輸出引數儲存過程
---輸出指定員工的姓名和工資
CREATE OR REPLACE PROCEDURE pro_demo2(NO emp.empno%TYPE,NAME out emp.ename%TYPE,salary out emp.sal%TYPE)
IS
BEGIN
SELECT ename,sal INTO NAME,salary FROM emp WHERE empno=NO;
END; --使用匿名塊呼叫儲存過程
DECLARE
v_name VARCHAR2(30);
v_sal NUMBER(7);
BEGIN
pro_demo2(&no,v_name,v_sal);
dbms_output.put_line(v_name || ',' || v_sal);
end; 五、函式
CREATE OR REPLACE FUNCTION 函式名(形參 資料型別,...) RETURN 資料型別
IS
定義部分;
BEGIN
執行部分;
exception
異常部分;
END; ---返回指定員工的年薪
CREATE OR REPLACE FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER
IS
v_salary NUMBER(10,2);
BEGIN
SELECT sal*12 INTO v_salary FROM emp WHERE empno=NO;
RETURN v_salary;
END; SELECT fun_demo1(7788) FROM dual; ---寫一個函式,返回使用者的姓名,入職日期,工資
CREATE OR REPLACE FUNCTION fun_demo2(NO emp.empno%TYPE) RETURN VARCHAR2
IS
v_ename emp.ename%TYPE;
v_hiredate varchar2(50);
v_sal emp.sal%TYPE;
v_info varchar2(200);
BEGIN
SELECT ename,to_char(hiredate,'yyyy-mm-dd'),sal INTO v_ename,v_hiredate,v_sal FROM emp WHERE empno=NO;
v_info:=v_ename ||','|| v_hiredate ||','|| v_sal;
RETURN v_info;
end; SELECT fun_demo2(7788) FROM dual; 儲存過程和函式的區別:
1.返回值的區別,函式返回值只有一個,而儲存過程是通過輸出引數來返回,可以有多個
2.呼叫的區別,函式可以在查詢語句中直接呼叫,而儲存過程必須單獨呼叫
3.應用場合的區別,函式一般用來計算並返回計算的結果,而儲存過程一般用來執行特定的操作,如建立表、建立使用者等DDL語句 五、包,裡面包含的內容:儲存過程,函式
語法:包括兩個部分
宣告部分:
CREATE OR REPLACE PACKAGE 包名
IS
宣告內容;
END; 包體的實體:
CREATE OR REPLACE PACKAGE BODY 包名
is
實現部分;
end; CREATE OR REPLACE PACKAGE pac_demo1
IS
PROCEDURE pro_demo1(NO emp.empno%TYPE,salary emp.sal%TYPE);
PROCEDURE pro_demo2(NO emp.empno%TYPE);
FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER;
end; create or replace package body pac_demo1
IS
PROCEDURE pro_demo1(NO emp.empno%TYPE,salary emp.sal%TYPE)
is
BEGIN
UPDATE emp SET sal=salary WHERE empno=NO;
END;
PROCEDURE pro_demo2(NO emp.empno%TYPE)
IS
BEGIN
DELETE FROM emp WHERE empno=NO;
END;
FUNCTION fun_demo1(NO emp.empno%TYPE) RETURN NUMBER
IS
v_salary number(10,2);
BEGIN
SELECT sal*12 INTO v_salary FROM emp WHERE empno=NO;
RETURN v_salary;
END;
end; CALL pac_demo1.pro_demo1(7788,20000);
SELECT * FROM emp;
CALL pac_demo1.pro_demo2(7788);
select pac_demo1.fun_demo1(7369) from dual; --1.建立一個包,包含一個為僱員加薪的過程,一個為僱員減薪的過程
CREATE OR REPLACE PACKAGE pac_test1
IS
PROCEDURE addsal(NO emp.empno%TYPE,addsal emp.sal%TYPE);
procedure minussal(no emp.empno%type,minussal emp.sal%type);
END; CREATE OR REPLACE PACKAGE body pac_test1
IS
PROCEDURE addsal(NO emp.empno%TYPE,addsal emp.sal%TYPE)
is
BEGIN
UPDATE emp SET sal=sal+addsal WHERE empno=NO;
end;
PROCEDURE minussal(NO emp.empno%TYPE,minussal emp.sal%TYPE)
IS
BEGIN
UPDATE emp SET sal=sal-minussal WHERE empno=NO;
end;
END; --2.編寫一個過程,驗證使用者登陸。如果使用者名稱、密碼匹配,輸出Y,否則輸出N emp表中的ename為使用者名稱 empno為密碼
CREATE OR REPLACE PROCEDURE pro_test2(username VARCHAR2,PASSWORD NUMBER,flag out VARCHAR2)
IS
v_count number(2);
BEGIN
SELECT count(empno) INTO v_count FROM emp WHERE ename=username AND empno=PASSWORD;
IF v_count>0 THEN flag:='Y';
ELSE flag:='N';
END IF;
END; --3.編寫一個函式,根據僱員編號,計算調整後的工資
如果該僱員從事經理工作,且工資大於3000,則工資上漲20%,否則上漲35%
其他情況均上漲10%,輸出僱員編號、姓名、上漲後的工資 CREATE OR REPLACE FUNCTION fun_test3(NO emp.empno%TYPE) RETURN VARCHAR2
IS
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
v_newsal emp.sal%TYPE;
v_job emp.job%type;
v_info varchar2(100);
BEGIN
SELECT ename,sal,JOB INTO v_ename,v_sal,v_job FROM emp WHERE empno=NO;
IF upper(v_job)='MANAGER' THEN
IF v_sal>3000 THEN
v_newsal:=v_sal*1.2;
ELSE v_newsal:=v_sal*1.35;
END IF;
ELSE v_newsal:=v_sal*1.1;
END IF;
v_info:= NO || ',' || v_ename || ',' || v_newsal;
RETURN v_info;
end; --4.建立一個包
包中含有一個儲存過程,實現漲工資的功能,輸入僱員姓名,如果其工作年限超過20年,工資增加2000
工作年限在10-20年,工資增加1000,工作年限在5-10年,工資增加500,輸出僱員姓名和增漲後的工資
包中還含有一個函式,實現輸入工資,判斷工資如果大於4500,返回1,否則返回0 CREATE OR REPLACE PACKAGE pac_test4
IS
PROCEDURE pro_addsal(NAME emp.ename%TYPE,info out VARCHAR2);
FUNCTION fun_sal(salary emp.sal%TYPE) RETURN NUMBER;
end; CREATE OR REPLACE PACKAGE body pac_test4
IS
PROCEDURE pro_addsal(NAME emp.ename%TYPE,info out VARCHAR2)
IS
v_year NUMBER(5);
v_sal emp.sal%TYPE;
BEGIN
SELECT trunc(months_between(SYSDATE,hiredate)/12),sal INTO v_year,v_sal FROM emp WHERE upper(ename)=upper(NAME);
IF v_year>20 THEN v_sal:=v_sal+2000;
elsif v_year>=10 THEN v_sal:=v_sal+1000;
elsif v_year>=5 THEN v_sal:=v_sal+500;
END IF;
info:=NAME || ','||v_sal;
end;
FUNCTION fun_sal(salary emp.sal%TYPE) RETURN NUMBER
IS
v_flag NUMBER(1);
BEGIN
IF salary>4500 THEN
v_flag:=1;
ELSE v_flag:=0;
END IF;
RETURN v_flag;
end;
END; 六、遊標:
1、顯示遊標(查)、隱式遊標(增刪改)
使用顯示遊標有四個步驟:
(01):宣告遊標:cursor 遊標名 IS 查詢語句;
(02):開啟遊標:open 遊標名;
(03):獲取資料:fetch 遊標名 INTO 變數名;
(04):關閉遊標:close 遊標名; 遊標屬性:
%found:是否發現數據,如果發現,返回true,否則返回false
%notfound:是否沒有資料,如果沒有,返回true,否則返回false
%isopen:是否開啟,如果開啟,,返回true,否則返回false
%rowcount:返回涉及的行數 DECLARE
CURSOR cur IS SELECT * FROM dept;
v_dept dept%rowtype;
BEGIN
OPEN cur;
fetch cur INTO v_dept;
loop
dbms_output.put_line(v_dept.deptno || ','|| v_dept.dname || ','||v_dept.loc);
fetch cur INTO v_dept;
exit WHEN cur%notfound;
END loop;
CLOSE cur;
end; ---使用for迴圈讀取遊標指向的資料,開啟遊標、獲取遊標資料、關閉遊標都自動
DECLARE
CURSOR cur IS SELECT * FROM dept;
BEGIN
FOR v_dept IN cur
loop
dbms_output.put_line(v_dept.deptno || ','|| v_dept.dname || ','||v_dept.loc);
END loop;
end; 2、隱式遊標:遊標名為SQL,增刪改 ---修改指定員工的工資,如果員工不存在,提示員工不存在,如果存在,輸出更新資料的行數
BEGIN
UPDATE emp SET sal=sal*1.2 WHERE empno=&no;
IF SQL%found THEN
dbms_output.put_line('更新資料的行數為:' || SQL%rowcount);
ELSE
dbms_output.put_line('對不起,該使用者不存在');
END IF;
end; 六、異常:
1、預定義異常:有異常號也有異常名
DECLARE
v_emp emp%rowtype;
BEGIN
SELECT * INTO v_emp FROM emp WHERE empno=&no;
exception
WHEN no_data_found THEN
dbms_output.put_line('使用者不存在');
WHEN too_many_rows THEN
dbms_output.put_line('返回了多行資料');
WHEN others THEN
dbms_output.put_line('程式出現了錯誤');
END; 2、非預定義異常:有異常號沒有異常名
3、自定義異常:沒有異常號也沒有異常名 七、觸發器
1、DML觸發器: CREATE OR REPLACE TRIGGER 觸發器名
AFTER|BEFORE INSERT|UPDATE|DELETE ON 表名
[FOR EACH ROW] ---行觸 發器
BEGIN
執行體;
end; ---如果有人刪除emp表中的資料,給出警告資訊
CREATE OR REPLACE trigger tri_demo1
AFTER DELETE ON emp
BEGIN
dbms_output.put_line('有人刪除了emp表中的資料,請注意');
end; DELETE FROM emp WHERE empno=7566; CREATE OR REPLACE TRIGGER tri_demo1
AFTER DELETE or update or insert ON emp
BEGIN
IF deleting THEN
dbms_output.put_line('有人在刪除emp表的資料');
elsif inserting THEN
dbms_output.put_line('有人新增了資料');
elsif updating THEN
dbms_output.put_line('有人修改了資料');
end if;
END; DELETE INSERT UPDATE
:NEW 無 有效 有效
:old 有效 無 有效 CREATE OR REPLACE TRIGGER tri_demo3
before DELETE OR UPDATE OR INSERT ON emp
for each row
BEGIN
IF deleting THEN
dbms_output.put_line('有人在刪除emp表的資料');
dbms_output.put_line(:old.ename ||','||:old.sal);
elsif inserting THEN
dbms_output.put_line('有人新增了資料');
dbms_output.put_line(:new.ename ||','||:new.sal);
elsif updating THEN
dbms_output.put_line('有人修改了資料');
dbms_output.put_line('原資料為:'||:OLD.ename ||','||:OLD.sal);
dbms_output.put_line('修改後的資料為:'||:new.ename ||','||:new.sal);
END IF;
END; 語句觸發器:無論增加、刪除、修改多少行資料,觸發器只觸發一次
行觸發器:增加、刪除、修改對於每一行涉及的資料,觸發器都會執行 INSERT INTO emp(empno,ename,sal) VALUES(1000,'bbb',6000);
commit; DELETE FROM emp WHERE deptno=10;
commit;