PL-SQL經(jīng)典試題

  1. 準(zhǔn)備工作:

set serveroutput on

 

hellowrold 程序

 

begin

dbms_output.put_line('hello world');

end;

/

 

[語(yǔ)法格式]

--declare

??--聲明的變量、類(lèi)型、游標(biāo)

begin

??--程序的執(zhí)行部分(類(lèi)似于java里的main()方法)

??dbms_output.put_line('helloworld');

--exception

??--針對(duì)begin塊中出現(xiàn)的異常,提供處理的機(jī)制

??--when .... then ...

??--when ?.... then ...

end;

 

*******************************************************************************

基本語(yǔ)法

*******************************************************************************

  1. 使用一個(gè)變量

 

declare

??--聲明一個(gè)變量

??v_name varchar2(25);

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select last_name into v_name

?from employees

?where employee_id = 186;

 

?-- 打印變量的值

?dbms_output.put_line(v_name);

end;

 

  1. 使用多個(gè)變量

 

declare

??--聲明變量

??v_name varchar2(25);

??v_email varchar2(25);

??v_salary number(8, 2);

??v_job_id varchar2(10);

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

??--被賦值的變量與SELECT中的列名要一一對(duì)應(yīng)

?select last_name, email, salary, job_id into v_name, v_email, v_salary, v_job_id

?from employees

?where employee_id = 186;

 

?-- 打印變量的值

?dbms_output.put_line(v_name || ', ' || v_email || ', ' || ?v_salary || ', ' || ?v_job_id);

end;

----------------------------------------------------------------

記錄類(lèi)型

----------------------------------------------------------------

3.1 自定義記錄類(lèi)型

 

declare

??--定義一個(gè)記錄類(lèi)型

??type customer_type is record(

????v_cust_name varchar2(20),

????v_cust_id number(10));

 

??--聲明自定義記錄類(lèi)型的變量

??v_customer_type customer_type;

begin

??v_customer_type.v_cust_name := '劉德華';

??v_customer_type.v_cust_id := 1001;

 

??dbms_output.put_line(v_customer_type.v_cust_name||','||v_customer_type.v_cust_id);

end;

 

3.2 自定義記錄類(lèi)型

 

declare

??--定義一個(gè)記錄類(lèi)型

??type emp_record is record(

????v_name varchar2(25),

????v_email varchar2(25),

????v_salary number(8, 2),

????v_job_id varchar2(10));

 

??--聲明自定義記錄類(lèi)型的變量

??v_emp_record emp_record;

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select last_name, email, salary, job_id into v_emp_record

?from employees

?where employee_id = 186;

 

?-- 打印變量的值

?dbms_output.put_line(v_emp_record.v_name || ', ' || v_emp_record.v_email || ', ' || ?v_emp_record.v_salary || ', ' || ?v_emp_record.v_job_id);

end;

 

  1. 使用 %type 定義變量,動(dòng)態(tài)的獲取數(shù)據(jù)的聲明類(lèi)型

 

declare

??--定義一個(gè)記錄類(lèi)型

??type emp_record is record(

????v_name employees.last_name%type,

????v_email employees.email%type,

????v_salary employees.salary%type,

????v_job_id employees.job_id%type);

 

??--聲明自定義記錄類(lèi)型的變量

??v_emp_record emp_record;

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select last_name, email, salary, job_id into v_emp_record

?from employees

?where employee_id = 186;

 

?-- 打印變量的值

?dbms_output.put_line(v_emp_record.v_name || ', ' || v_emp_record.v_email || ', ' || ?v_emp_record.v_salary || ', ' || ?v_emp_record.v_job_id);

end;

 

 

  1. 使用 %rowtype

 

declare

--聲明一個(gè)記錄類(lèi)型的變量

??v_emp_record employees%rowtype;

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select * into v_emp_record

?from employees

?where employee_id = 186;

 

?-- 打印變量的值

?dbms_output.put_line(v_emp_record.last_name || ', ' || v_emp_record.email || ', ' || ?v_emp_record.salary || ', ' || ?v_emp_record.job_id ?|| ', ' || v_emp_record.hire_date);

end;

 

6.1 賦值語(yǔ)句:通過(guò)變量實(shí)現(xiàn)查詢(xún)語(yǔ)句

 

declare

??v_emp_record employees%rowtype;

??v_employee_id employees.employee_id%type;

begin

??--使用賦值符號(hào)位變量進(jìn)行賦值

??v_employee_id := 186;

 

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select * into v_emp_record

?from employees

?where employee_id = v_employee_id;

 

?-- 打印變量的值

?dbms_output.put_line(v_emp_record.last_name || ', ' || v_emp_record.email || ', ' || ?

v_emp_record.salary || ', ' || ?v_emp_record.job_id ?|| ', ' || v_emp_record.hire_date);

end;

 

6.2 ?通過(guò)變量實(shí)現(xiàn)DELETE、INSERT、UPDATE等操作

 

declare

??v_emp_id employees.employee_id%type;

 

begin

??v_emp_id := 109;

??delete from employees

??where employee_id = v_emp_id;

??--commit;

end;

*******************************************************************************

流程控制

*******************************************************************************

-----------------------------------------------------

條件判斷

-----------------------------------------------------

  1. 使用 IF ... THEN ... ELSIF ... THEN ...ELSE ... END IF;

 

要求: 查詢(xún)出 150號(hào) 員工的工資, 若其工資大于或等于 10000 則打印 'salary >= 10000';

若在 5000 到 10000 之間, 則打印 '5000<= salary < 10000'; 否則打印 'salary < 5000'

(方法一)

declare

??v_salary employees.salary%type;

begin

??--通過(guò) select ... into ... 語(yǔ)句為變量賦值

?select salary into v_salary

?from employees

?where employee_id = 150;

 

?dbms_output.put_line('salary: ' || v_salary);

 

?-- 打印變量的值

?if v_salary >= 10000 then

????dbms_output.put_line('salary >= 10000');

?elsif v_salary >= 5000 then

????dbms_output.put_line('5000 <= salary < 10000');

?else

????dbms_output.put_line('salary < 5000');

?end if;

(方法二)

declare

?????v_emp_name employees.last_name%type;

?????v_emp_sal employees.salary%type;

?????v_emp_sal_level varchar2(20);

begin

?????select last_name,salary into v_emp_name,v_emp_sal from employees where employee_id = 150;

 

?????if(v_emp_sal >= 10000) then v_emp_sal_level := 'salary >= 10000';

?????elsif(v_emp_sal >= 5000) then v_emp_sal_level := '5000<= salary < 10000';

?????else v_emp_sal_level := 'salary < 5000';

?????end if;

 

?????dbms_output.put_line(v_emp_name||','||v_emp_sal||','||v_emp_sal);

end;

 

7+ 使用 CASE ... WHEN ... THEN ...ELSE ... END 完成上面的任務(wù)

 

declare

???????v_sal employees.salary%type;

???????v_msg varchar2(50);

begin ????

???????select salary into v_sal

???????from employees

???????where employee_id = 150;

 

???????--case 不能向下面這樣用

???????/*

???????case v_sal when salary >= 10000 then v_msg := '>=10000'

??????????????????when salary >= 5000 then v_msg := '5000<= salary < 10000'

??????????????????else v_msg := 'salary < 5000'

???????end;

???????*/

 

???????v_msg :=

?????????????case trunc(v_sal / 5000)

??????????????????when 0 then 'salary < 5000'

??????????????????when 1 then '5000<= salary < 10000'

??????????????????else 'salary >= 10000'

?????????????end;

 

???????dbms_output.put_line(v_sal ||','||v_msg);

end;

 

  1. 使用 CASE ... WHEN ... THEN ... ELSE ... END;

要求: 查詢(xún)出 122 號(hào)員工的 JOB_ID, 若其值為 'IT_PROG', 則打印 'GRADE: A';

'AC_MGT', 打印 'GRADE B',

'AC_ACCOUNT', 打印 'GRADE C';

否則打印 'GRADE D'

 

declare

???????--聲明變量

???????v_grade char(1);

???????v_job_id employees.job_id%type;

begin

???????select job_id into v_job_id

???????from employees

???????where employee_id = 122;

 

???????dbms_output.put_line('job_id: ' || v_job_id);

 

???????--根據(jù) v_job_id 的取值, 利用 case 字句為 v_grade 賦值

???????v_grade := ?

???????????????case v_job_id when 'IT_PROG' then 'A'

?????????????????????????????when 'AC_MGT' then 'B'

?????????????????????????????when 'AC_ACCOUNT' then 'C'

?????????????????????????????else 'D'

????????????????end;

 

???????dbms_output.put_line('GRADE: ' || v_grade);

end;

-----------------------------------------------------

循環(huán)結(jié)構(gòu)

-----------------------------------------------------

  1. 使用循環(huán)語(yǔ)句打印 1 - 100.(三種方式)

 

1). ?LOOP ... EXIT WHEN ... END LOOP

declare

???????--初始化條件

???????v_i number(3) := 1;

begin

???????loop

???????--循環(huán)體

????????dbms_output.put_line(v_i);

--循環(huán)條件

????????exit when v_i = 100;

--迭代條件

????????v_i := v_i + 1;

???????end loop;

end;

 

2). WHILE ... LOOP ... END LOOP

declare

???????--初始化條件

???????v_i number(3) := 1;

begin

???????--循環(huán)條件

???????while v_i <= 100 loop

?????--循環(huán)體

?????????????dbms_output.put_line(v_i);

?????--迭代條件

?????????????v_i := v_i + 1;

???????end loop;

end;

 

3).

begin

???????for i in 1 .. 100 loop

?????????????dbms_output.put_line(i);

???????end loop;

end;

 

  1. 綜合使用 if, while 語(yǔ)句, 打印 1 - 100 之間的所有素?cái)?shù)

(素?cái)?shù): 有且僅用兩個(gè)正約數(shù)的整數(shù), 2, 3, 5, 7, 11, 13, ...).

declare

??v_flag number(1):=1;

??v_i number(3):=2;

??v_j number(2):=2;

begin

 

??while (v_i<=100) loop

????????while v_j <= sqrt(v_i) loop

??????????????if (mod(v_i,v_j)=0) then v_flag:= 0;end if;

??????????????v_j :=v_j +1;

????????end loop;

????????if(v_flag=1) then dbms_output.put_line(v_i);end if;

 

????????v_flag :=1;

????????v_j := 2;

????????v_i :=v_i +1;

???end loop;

 

end;

 

 

(法二)使用for循環(huán)實(shí)現(xiàn)1-100之間的素?cái)?shù)的輸出

declare

??--標(biāo)記值, 若為 1 則是素?cái)?shù), 否則不是

??v_flag number(1) := 0;

begin

???for i in 2 .. 100 loop

 

???????v_flag := 1; ????

 

???????for j in 2 .. sqrt(i) loop

???????????if i mod j = 0 then

??????????????v_flag := 0;

???????????end if; ???????

???????end loop;

 

???????if v_flag = 1 then

???????????dbms_output.put_line(i);

???????end if;

 

???end loop;

end;

 

  1. 使用 goto

declare

??--標(biāo)記值, 若為 1 則是素?cái)?shù), 否則不是

??v_flag number(1) := 0;

begin

???for i in 2 .. 100 loop

???????v_flag := 1; ????

 

???????for j in 2 .. sqrt(i) loop

???????????if i mod j = 0 then

??????????????v_flag := 0;

??????????????goto label;

???????????end if; ???????

???????end loop;

 

???????<<label>>

???????if v_flag = 1 then

???????????dbms_output.put_line(i);

???????end if;

 

???end loop;

end;

 

11+.打印1——100的自然數(shù),當(dāng)打印到50時(shí),跳出循環(huán),輸出“打印結(jié)束”

(方法一)

begin

??for i in 1..100 loop

??????dbms_output.put_line(i);

??????if(i = 50) then

??????goto label;

??????end if;

??end loop;

 

??????<<label>>

??????dbms_output.put_line('打印結(jié)束');

 

end;

(方法二)

begin

??for i in 1..100 loop

??????dbms_output.put_line(i);

??????if(i mod 50 = 0) then dbms_output.put_line('打印結(jié)束');

??????exit;

??????end if;

??end loop;

end;

******************************************************************************游標(biāo)的使用

*******************************************************************************12.1 使用游標(biāo)

要求: 打印出 80 部門(mén)的所有的員工的工資:salary: xxx

 

declare

??--1. 定義游標(biāo)

??cursor salary_cursor is select salary from employees where department_id = 80;

??v_salary employees.salary%type;

begin

?--2. 打開(kāi)游標(biāo)

?open salary_cursor;

 

?--3. 提取游標(biāo)

?fetch salary_cursor into v_salary;

 

?--4. 對(duì)游標(biāo)進(jìn)行循環(huán)操作: 判斷游標(biāo)中是否有下一條記錄

while salary_cursor%found loop

??????dbms_output.put_line('salary: ' || v_salary);

??????fetch salary_cursor into v_salary;

end loop; ?

 

?--5. 關(guān)閉游標(biāo)

?close ?salary_cursor;

end;

 

12.2 使用游標(biāo)

要求: 打印出 80 部門(mén)的所有的員工的工資: Xxx 's salary is: xxx

 

declare

??cursor sal_cursor is select salary ,last_name from employees where department_id = 80;

??v_sal number(10);

??v_name varchar2(20);

begin

??open sal_cursor;

 

??fetch sal_cursor into v_sal,v_name;

 

??while sal_cursor%found loop

????????dbms_output.put_line(v_name||'`s salary is '||v_sal);

????????fetch sal_cursor into v_sal,v_name;

??end loop;

 

??close sal_cursor;

 

end;

 

  1. 使用游標(biāo)的練習(xí):

打印出 manager_id 為 100 的員工的 last_name, email, salary 信息(使用游標(biāo), 記錄類(lèi)型)

 

declare ?

???????????--聲明游標(biāo) ???

???????????cursor emp_cursor is select last_name, email, salary from employees where manager_id = 100;

 

???????????--聲明記錄類(lèi)型

???????????type emp_record is record(

????????????????name employees.last_name%type,

????????????????email employees.email%type,

????????????????salary employees.salary%type

???????????);

 

???????????-- 聲明記錄類(lèi)型的變量

???????????v_emp_record emp_record;

begin

???????????--打開(kāi)游標(biāo)

???????????open emp_cursor;

 

???????????--提取游標(biāo)

???????????fetch emp_cursor into v_emp_record;

 

???????????--對(duì)游標(biāo)進(jìn)行循環(huán)操作

???????????while emp_cursor%found loop

??????????????????dbms_output.put_line(v_emp_record.name || ', ' || v_emp_record.email || ', ' || v_emp_record.salary ); ???????????????

??????????????????fetch emp_cursor into v_emp_record;

???????????end loop;

 

???????????--關(guān)閉游標(biāo)

???????????close emp_cursor;

end;

(法二:使用for循環(huán))

declare

 

??????cursor emp_cursor is

??????select last_name,email,salary

??????from employees

??????where manager_id = 100;

 

begin

 

 

??????for v_emp_record in emp_cursor loop

??????????dbms_output.put_line(v_emp_record.last_name||','||v_emp_record.email||','||v_emp_record.salary);

??????end loop;

end;

 

  1. 利用游標(biāo), 調(diào)整公司中員工的工資:

 

????工資范圍 ??????調(diào)整基數(shù)

????0 - 5000 ??????5%

????5000 - 10000 ??3%

????10000 - 15000 ?2%

????15000 - ???????1%

 

declare

????--定義游標(biāo)

????cursor emp_sal_cursor is select salary, employee_id from employees;

 

????--定義基數(shù)變量

????temp number(4, 2);

 

????--定義存放游標(biāo)值的變量

????v_sal employees.salary%type;

????v_id employees.employee_id%type;

begin

????--打開(kāi)游標(biāo)

????open emp_sal_cursor;

 

????--提取游標(biāo)

????fetch emp_sal_cursor into v_sal, v_id;

 

????--處理游標(biāo)的循環(huán)操作

????while emp_sal_cursor%found loop

??????????--判斷員工的工資, 執(zhí)行 update 操作

??????????--dbms_output.put_line(v_id || ': ' || v_sal);

 

??????????if v_sal <= 5000 then

?????????????temp := 0.05;

??????????elsif v_sal<= 10000 then

?????????????temp := 0.03; ??

??????????elsif v_sal <= 15000 then

?????????????temp := 0.02;

??????????else

?????????????temp := 0.01;

??????????end if;

 

??????????--dbms_output.put_line(v_id || ': ' || v_sal || ', ' || temp);

??????????update employees set salary = salary * (1 + temp) where employee_id = v_id;

 

??????????fetch emp_sal_cursor into v_sal, v_id;

????end loop;

????--關(guān)閉游標(biāo)

????close emp_sal_cursor;

end;

 

使用SQL中的 decode 函數(shù)

 

update employees set salary = salary * (1 + (decode(trunc(salary/5000), 0, 0.05,

??????????????????????????????????????????????????????????1, 0.03,

??????????????????????????????????????????????????????????2, 0.02,

??????????????????????????????????????????????????????????0.01)))

 

  1. 利用游標(biāo) for 循環(huán)完成 14.

 

declare

????--定義游標(biāo)

????cursor emp_sal_cursor is select salary, employee_id id from employees;

 

????--定義基數(shù)變量

????temp number(4, 2);

begin

????--處理游標(biāo)的循環(huán)操作

????for c in emp_sal_cursor loop

??????????--判斷員工的工資, 執(zhí)行 update 操作

??????????--dbms_output.put_line(c.employee_id || ': ' || c.salary);

 

??????????if c.salary <= 5000 then

?????????????temp := 0.05;

??????????elsif c.salary <= 10000 then

?????????????temp := 0.03; ??

??????????elsif c.salary <= 15000 then

?????????????temp := 0.02;

??????????else

?????????????temp := 0.01;

??????????end if;

 

??????????--dbms_output.put_line(v_id || ': ' || v_sal || ', ' || temp);

??????????update employees set salary = salary * (1 + temp) where employee_id = c.id;

????end loop;

end;

 

16*. 帶參數(shù)的游標(biāo)

 

declare

????--定義游標(biāo)

????cursor emp_sal_cursor(dept_id number, sal number) is

???????????select salary + 1000 sal, employee_id id

???????????from employees

???????????where department_id = dept_id and salary > sal;

 

????--定義基數(shù)變量

????temp number(4, 2);

begin

????--處理游標(biāo)的循環(huán)操作

????for c in emp_sal_cursor(sal => 4000, dept_id => 80) loop

??????????--判斷員工的工資, 執(zhí)行 update 操作

??????????--dbms_output.put_line(c.id || ': ' || c.sal);

 

??????????if c.sal <= 5000 then

?????????????temp := 0.05;

??????????elsif c.sal <= 10000 then

?????????????temp := 0.03; ??

??????????elsif c.sal <= 15000 then

?????????????temp := 0.02;

??????????else

?????????????temp := 0.01;

??????????end if;

 

??????????dbms_output.put_line(c.sal || ': ' || c.id || ', ' || temp);

??????????--update employees set salary = salary * (1 + temp) where employee_id = c.id;

????end loop;

end;

 

  1. 隱式游標(biāo): 更新指定員工 salary(漲工資 10),如果該員工沒(méi)有找到,則打印”查無(wú)此人” 信息

 

begin

?????????update employees set salary = salary + 10 where employee_id = 1005;

 

?????????if sql%notfound then

????????????dbms_output.put_line('查無(wú)此人!');

?????????end if;

end;

 

*******************************************************************************

異常處理

*******************************************************************************

[預(yù)定義異常]

declare

 

??v_sal employees.salary%type;

begin

??select salary into v_sal

??from employees

??where employee_id >100;

 

??dbms_output.put_line(v_sal);

 

exception

??when Too_many_rows then dbms_output.put_line('輸出的行數(shù)太多了');

end;

 

[非預(yù)定義異常]

declare

 

??v_sal employees.salary%type;

??--聲明一個(gè)異常

??delete_mgr_excep exception;

??--把自定義的異常和oracle的錯(cuò)誤關(guān)聯(lián)起來(lái)

??PRAGMA EXCEPTION_INIT(delete_mgr_excep,-2292);

begin

??delete from employees

??where employee_id = 100;

 

??select salary into v_sal

??from employees

??where employee_id >100;

 

??dbms_output.put_line(v_sal);

 

exception

??when Too_many_rows then dbms_output.put_line('輸出的行數(shù)太多了');

??when delete_mgr_excep then dbms_output.put_line('Manager不能直接被刪除');

end;

 

[用戶(hù)自定義異常]

declare

 

??v_sal employees.salary%type;

??--聲明一個(gè)異常

??delete_mgr_excep exception;

??--把自定義的異常和oracle的錯(cuò)誤關(guān)聯(lián)起來(lái)

??PRAGMA EXCEPTION_INIT(delete_mgr_excep,-2292);

 

??--聲明一個(gè)異常

??too_high_sal exception;

begin

 

??select salary into v_sal

??from employees

??where employee_id =100;

 

??if v_sal > 1000 then

?????raise too_high_sal;

??end if;

 

??delete from employees

??where employee_id = 100;

 

??dbms_output.put_line(v_sal);

 

exception

??when Too_many_rows then dbms_output.put_line('輸出的行數(shù)太多了');

??when delete_mgr_excep then dbms_output.put_line('Manager不能直接被刪除');

??--處理異常

??when too_high_sal then dbms_output.put_line('工資過(guò)高了');

end;

 

  1. 異常的基本程序:

通過(guò) select ... into ... 查詢(xún)某人的工資, 若沒(méi)有查詢(xún)到, 則輸出 "未找到數(shù)據(jù)"

 

declare

??--定義一個(gè)變量

??v_sal employees.salary%type;

begin

??--使用 select ... into ... 為 v_sal 賦值

??select salary into v_sal from employees where employee_id = 1000;

??dbms_output.put_line('salary: ' || v_sal);

exception

??when No_data_found then

???????dbms_output.put_line('未找到數(shù)據(jù)');

end;

 

 

declare

??--定義一個(gè)變量

??v_sal employees.salary%type;

begin

??--使用 select ... into ... 為 v_sal 賦值

??select salary into v_sal from employees;

??dbms_output.put_line('salary: ' || v_sal);

exception

??when No_data_found then

???????dbms_output.put_line('未找到數(shù)據(jù)!');

??when Too_many_rows then

???????dbms_output.put_line('數(shù)據(jù)過(guò)多!'); ????

end;

 

  1. 更新指定員工工資,如工資小于300,則加100;對(duì) NO_DATA_FOUND 異常, TOO_MANY_ROWS 進(jìn)行處理.

declare

???v_sal employees.salary%type;

begin

???select salary into v_sal from employees where employee_id = 100;

 

???if(v_sal < 300) then update employees set salary = salary + 100 where employee_id = 100;

???else dbms_output.put_line('工資大于300');

???end if;

exception

???when no_data_found then dbms_output.put_line('未找到數(shù)據(jù)');

????when too_many_rows then dbms_output.put_line('輸出的數(shù)據(jù)行太多');

end;

 

  1. 處理非預(yù)定義的異常處理: "違反完整約束條件"

 

declare

??--1. 定義異常

??temp_exception exception;

 

??--2. 將其定義好的異常情況,與標(biāo)準(zhǔn)的 ORACLE 錯(cuò)誤聯(lián)系起來(lái),使用 EXCEPTION_INIT 語(yǔ)句

??PRAGMA EXCEPTION_INIT(temp_exception, -2292);

begin

??delete from employees where employee_id = 100;

 

exception

??--3. 處理異常

??when temp_exception then

???????dbms_output.put_line('違反完整性約束!');

end;

 

  1. 自定義異常: 更新指定員工工資,增加100;若該員工不存在則拋出用戶(hù)自定義異常: no_result

 

declare

??--自定義異常 ??????????????????????????????????

??no_result exception; ??

begin

??update employees set salary = salary + 100 where employee_id = 1001;

 

??--使用隱式游標(biāo), 拋出自定義異常

??if sql%notfound then

?????raise no_result;

??end if; ?

 

exception

 

??--處理程序拋出的異常

??when no_result then

?????dbms_output.put_line('更新失敗');

end;

*******************************************************************************

存儲(chǔ)函數(shù)和過(guò)程

*******************************************************************************

[存儲(chǔ)函數(shù):有返回值,創(chuàng)建完成后,通過(guò)select function() from dual;執(zhí)行]

[存儲(chǔ)過(guò)程:由于沒(méi)有返回值,創(chuàng)建完成后,不能使用select語(yǔ)句,只能使用pl/sql塊執(zhí)行]

 

[格式]

--函數(shù)的聲明(有參數(shù)的寫(xiě)在小括號(hào)里)

create or replace function func_name(v_param varchar2)

--返回值類(lèi)型

return varchar2

is

--PL/SQL塊變量、記錄類(lèi)型、游標(biāo)的聲明(類(lèi)似于前面的declare的部分)

begin

--函數(shù)體(可以實(shí)現(xiàn)增刪改查等操作,返回值需要return)

???????return 'helloworld'|| v_param;

end;

 

22.1 函數(shù)的 helloworld: 返回一個(gè) "helloworld" 的字符串

 

create or replace function hello_func

return varchar2

is

begin

???????return 'helloworld';

end;

 

執(zhí)行函數(shù)

 

begin

????dbms_output.put_line(hello_func());

end;

 

或者: select hello_func() from dual;

 

22.2 返回一個(gè)"helloworld: atguigu"的字符串,其中atguigu 由執(zhí)行函數(shù)時(shí)輸入。

 

--函數(shù)的聲明(有參數(shù)的寫(xiě)在小括號(hào)里)

create or replace function hello_func(v_logo varchar2)

--返回值類(lèi)型

return varchar2

is

--PL/SQL塊變量的聲明

begin

--函數(shù)體

???????return 'helloworld'|| v_logo;

end;

 

22.3 創(chuàng)建一個(gè)存儲(chǔ)函數(shù),返回當(dāng)前的系統(tǒng)時(shí)間

create or replace function func1

return date

is

--定義變量

v_date date;

begin

-函數(shù)體

--v_date := sysdate;

????select sysdate into v_date from dual;

???????dbms_output.put_line('我是函數(shù)哦');

 

???????return v_date;

end;

 

執(zhí)行法1:

select func1 from dual;

執(zhí)行法2:

declare

??v_date date;

begin

??v_date := func1;

??dbms_output.put_line(v_date);

end;

 

  1. 定義帶參數(shù)的函數(shù): 兩個(gè)數(shù)相加

 

create or replace function add_func(a number, b number)

return number

is

begin

???????return (a + b);

end;

 

執(zhí)行函數(shù)

 

begin

????dbms_output.put_line(add_func(12, 13));

end;

或者

????select add_func(12,13) from dual;

 

  1. 定義一個(gè)函數(shù): 獲取給定部門(mén)的工資總和, 要求:部門(mén)號(hào)定義為參數(shù), 工資總額定義為返回值.

 

create or replace function sum_sal(dept_id number)

???????return number

???????is

 

???????cursor sal_cursor is select salary from employees where department_id = dept_id;

???????v_sum_sal number(8) := 0; ??

begin

???????for c in sal_cursor loop

???????????v_sum_sal := v_sum_sal + c.salary;

???????end loop; ??????

 

???????--dbms_output.put_line('sum salary: ' || v_sum_sal);

???????return v_sum_sal;

end;

 

執(zhí)行函數(shù)

 

begin

????dbms_output.put_line(sum_sal(80));

end;

 

  1. 關(guān)于 OUT 型的參數(shù): 因?yàn)楹瘮?shù)只能有一個(gè)返回值, PL/SQL 程序可以通過(guò) OUT 型的參數(shù)實(shí)現(xiàn)有多個(gè)返回值

 

要求: 定義一個(gè)函數(shù): 獲取給定部門(mén)的工資總和 和 該部門(mén)的員工總數(shù)(定義為 OUT 類(lèi)型的參數(shù)).

要求: 部門(mén)號(hào)定義為參數(shù), 工資總額定義為返回值.

 

create or replace function sum_sal(dept_id number, total_count out number)

???????return number

???????is

 

???????cursor sal_cursor is select salary from employees where department_id = dept_id;

???????v_sum_sal number(8) := 0; ??

begin

???????total_count := 0;

 

???????for c in sal_cursor loop

???????????v_sum_sal := v_sum_sal + c.salary;

???????????total_count := total_count + 1;

???????end loop; ??????

 

???????--dbms_output.put_line('sum salary: ' || v_sum_sal);

???????return v_sum_sal;

end; ??

 

執(zhí)行函數(shù):

 

delare

??v_total number(3) := 0;

 

begin

????dbms_output.put_line(sum_sal(80, v_total));

????dbms_output.put_line(v_total);

end;

 

26*. 定義一個(gè)存儲(chǔ)過(guò)程: 獲取給定部門(mén)的工資總和(通過(guò) out 參數(shù)), 要求:部門(mén)號(hào)和工資總額定義為參數(shù)

 

create or replace procedure sum_sal_procedure(dept_id number, v_sum_sal out number)

???????is

 

???????cursor sal_cursor is select salary from employees where department_id = dept_id;

begin

???????v_sum_sal := 0;

 

???????for c in sal_cursor loop

???????????--dbms_output.put_line(c.salary);

???????????v_sum_sal := v_sum_sal + c.salary;

???????end loop; ??????

 

???????dbms_output.put_line('sum salary: ' || v_sum_sal);

end;

[執(zhí)行]

declare

?????v_sum_sal number(10) := 0;

begin

?????sum_sal_procedure(80,v_sum_sal);

end;

 

27*. 自定義一個(gè)存儲(chǔ)過(guò)程完成以下操作:

對(duì)給定部門(mén)(作為輸入?yún)?shù))的員工進(jìn)行加薪操作, 若其到公司的時(shí)間在

(? , 95) 期間, ???為其加薪 %5

[95 , 98)?????????????????%3 ??????????????????????????????????????????????????????????????????[98, ?) ?????????????????%1

得到以下返回結(jié)果: 為此次加薪公司每月需要額外付出多少成本(定義一個(gè) OUT 型的輸出參數(shù)).

 

create or replace procedure add_sal_procedure(dept_id number, temp out number)

 

is

 

???????cursor sal_cursor is select employee_id id, hire_date hd, salary sal from employees where department_id = dept_id;

???????a number(4, 2) := 0;

begin

???????temp := 0; ??????

 

???????for c in sal_cursor loop

???????????a := 0; ???

 

???????????if c.hd < to_date('1995-1-1', 'yyyy-mm-dd') then

??????????????a := 0.05;

???????????elsif c.hd < to_date('1998-1-1', 'yyyy-mm-dd') then

??????????????a := 0.03;

???????????else

??????????????a := 0.01;

???????????end if;

 

???????????temp := temp + c.sal * a;

???????????update employees set salary = salary * (1 + a) where employee_id = c.id;

???????end loop; ??????

end;

 

*******************************************************************************

觸發(fā)器

*******************************************************************************

一個(gè)helloworld級(jí)別的觸發(fā)器

create or replace trigger hello_trigger

after

update on employees

--for each row

begin

????dbms_output.put_line('hello...');

????--dbms_output.put_line('old.salary:'|| :OLD.salary||',new.salary'||:NEW.salary);

end;

然后執(zhí)行:update employees set salary = salary + 1000;

 

  1. 觸發(fā)器的 helloworld: 編寫(xiě)一個(gè)觸發(fā)器, 在向 emp 表中插入記錄時(shí), 打印 'helloworld'

 

create or replace trigger emp_trigger

after

insert on emp

for each row

begin

???????dbms_output.put_line('helloworld');

end;

 

  1. 行級(jí)觸發(fā)器: 每更新 employees 表中的一條記錄, 都會(huì)導(dǎo)致觸發(fā)器執(zhí)行

 

create or replace trigger employees_trigger

after

update on employees

for each row

begin

???????dbms_output.put_line('修改了一條記錄!');

end;

 

語(yǔ)句級(jí)觸發(fā)器: 一個(gè) update/delete/insert 語(yǔ)句只使觸發(fā)器執(zhí)行一次

 

create or replace trigger employees_trigger

after

update on employees

begin

???????dbms_output.put_line('修改了一條記錄!');

end;

 

  1. 使用 :new, :old 修飾符

 

create or replace trigger employees_trigger

after

update on employees

for each row

begin

???????dbms_output.put_line('old salary: ' || :old.salary || ', new salary: ' || :new.salary);

end;

 

  1. 編寫(xiě)一個(gè)觸發(fā)器, 在對(duì) my_emp 記錄進(jìn)行刪除的時(shí)候, 在 my_emp_bak 表中備份對(duì)應(yīng)的記錄

 

1). 準(zhǔn)備工作:

create table my_emp as select employee_id id, last_name name, salary sal from employees;

 

create table my_emp_bak as select employee_id id, last_name name, salary sal from employees where 1 = 2

 

2).

create or replace trigger bak_emp_trigger

???????before delete on my_emp

???????for each row

 

begin

???????insert into my_emp_bak values(:old.id, :old.name, :old.sal);

end;