一.pl/sql基礎
pl/sql分匿名塊和命名塊.
命名塊:存儲過程,函數,觸發器,包等.
pl/sql語句塊分3部分:
(1)聲明部分
(2)可執行部分
(3)異常處理部分
其中可執行部分是語句塊中唯一要求必須存在的部分,聲明部分和異常處理部分是可選的。
1.匿名塊語法:
DECLARE
declaration statements
BEGIN
executable statements
EXCEPTION
exception-handing statements
END;
2.聲明變量
語法:
identifier [CONSTANT] datatype [NOT NULL] [:= value | DEFAULT expr]
聲明變量方法1:
declare
v_first_name varchar2(50);
c_count constant number :=0; ---常量
v_hiredate date;
v_valid BOOLEAN NOT NULL DEFAULT TRUE;
聲明變量方法1:
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
//顯示僱員的姓名,工資,個人所得稅
set serveroutput on; declare v_ename varchar2(20); v_sal number(6,2); c_tax_rate constant number(3,2) :=0.06; ---稅率 v_tax_sal number(6,2); begin select ename,sal into v_ename,v_sal from emp where empno = &no; v_tax_sal := v_sal * c_tax_rate; ---賦值 dbms_output.put_line('v_ename: ' || v_ename); dbms_output.put_line('v_sal: ' || v_sal); dbms_output.put_line('v_tax_sal: ' || v_tax_sal); end;
3.標識符的命名規則
(1)定義變量,建議用v_,如v_ename
(2)定義常量,建議用c_,如c_tax_rate
(3)定義遊標,建議用_cursor作爲後綴,如emp_cursor
(4)定義表類型,建議用_table_type作爲後綴,如sal_table_type;
(5)定義表變量,建議用_table作爲後綴,例如sal_table;
4.PL/SQL編譯過程步驟
編譯過程包括語法檢查,綁定以及爲代碼生成。語法檢查涉及檢查PL/SQL代碼中的編譯錯誤。在糾正語法錯誤之後,會給每個變量分配內存地址,以保存ORACLE數據,這個過程成爲綁定。接下來,會產生PL/SQL語句塊的僞代碼,僞代碼是PL/SQL引擎的指令列表,對於命名語句塊,僞代碼會存儲在數據庫中,並在程序下一次執行時使用。
5.替代變量
在匿名PL/SQL塊中接受輸入參數使用&或者&&作爲替代變量
6.初始化變量用select into語法
//求emp表中的平均工資 SQL> set serveroutput on; SQL> SQL> declare 2 v_avg_sal number(6,2); 3 begin 4 select avg(sal) into v_avg_sal from emp; 5 dbms_output.put_line('v_avg_sal: ' || v_avg_sal); 6 end; 7 / ---表示執行 v_avg_sal: 2530.88 PL/SQL procedure successfully completed.
二.控制語句
7.if語句
if語法:
IF condition THEN
statements;
[ELSIF condition THEN
statements;]
[ELSE
statements;
]
END IF;
//如果工資小於2000,把僱員的薪水加薪50
setserveroutput on; declare v_sal emp.sal%type; begin select sal into v_sal from emp where lower(ename)=lower('&name'); if v_sal <2000 then update emp set sal=sal+50 where lower(ename)=lower('&name'); end if; end;
//如果job=PRESIDENT,sal=sal+200
job=MANAGER ,sal=sal+1000
other ,sal=sal+100
setserveroutput on; declare v_job emp.job%type; v_empno emp.empno%type; begin select job,empno into v_job,v_empno from emp where empno=&no; if v_job='PRESIDENT' then update emp set sal=sal+200 where empno=v_empno; elsif v_job='MANAGER' then update emp setsal=sal+1000 where empno=v_empno; else update emp set sal=sal+100 where empno=v_empno; endif; commit; end;
8.循環語句
//loop循環
loop
statements;
exit [when condition];
end loop;
//例子
create table tmp01 (id int); declare i int :=1; begin loop insert into tmp01 values (i); commit; exit when i >100; i := i+1; end loop; end;
//while循環
while condition loop
statement1;
statement2;
......
end loop;
//例子
declare i number :=1; begin while i <100 loop insert into tmp01 values (i); i := i+1; end loop; commit; end;
//FOR循環
for counter in [reverse] lower_bound .. upper_bound loop ---counter變量不需要定義
statement1;
statement2;
......
end loop;
//例子
begin for i in 1..100 loop insert into tmp01 values (i); end loop; commit; end;
//用替代變量輸入部門號,使用case語句判斷條件更新僱員工資
部門號爲10,僱員加薪10%
部門號爲20,僱員加薪8%
部門號爲30,僱員加薪15%
如果輸入其他數字,則顯示“該部門不存在”
declare v_deptno emp.deptno%type; begin v_deptno := &deptno; case v_deptno when 10 then update emp set sal=sal*1.1 where deptno=v_deptno; when 20 then update emp set sal=sal*1.08 where deptno=v_deptno; when 30 then update emp set sal=sal*1.15 where deptno=v_deptno; else dbms_output.put_line('deptno not exists'); end case; end;
9.SQL遊標
當執行select,insert,update,delete時,oracle會爲SQL語句分配相應的上下文區域(context area).oracle使用上下區域解析並執行相應的SQL語句,而遊標就是指向上下文區域的指針。
遊標包括隱式遊標和顯示遊標。其中隱式遊標也稱爲SQL遊標,專門用於處理select into,insert,update,delete語句。顯示遊標用於處理多行select語句。
SQL遊標屬性:sql%found,sql%notfound,sql%rowcount,sql%isopen等
(1)sql%isopen:用於確定SQL遊標是否打開。
(2)sql%found:用於確定SQL語句是否執行成功。
(3)sql%notfound:用於確定SQL語句是否執行成功。
(4)sql%rowcount:用於返回SQL語句所作用的總計行數。
//例子1
set serveroutput on; declare v_deptno emp.deptno%type := &no; begin update emp set sal = sal*1.05 where deptno=v_deptno; if sql%notfound then dbms_output.put_line('deptno is not exist.'); else dbms_output.put_line('sql execute successful.'); end if; end;
//例子2
set serveroutput on; declare v_deptno emp.deptno%type := &no; begin update emp set sal = nvl(sal,0)*1.05 where deptno=v_deptno; dbms_output.put_line('have '|| sql%rowcount || ' row have change.'); if sql%notfound then dbms_output.put_line('deptno is not exist.'); else dbms_output.put_line('sql execute successful.'); end if; end;
10.例子
用替代變量輸入客戶名(不區分大小寫)和所在城市,並修改客戶所在城市,如果客戶不在,則顯示“該客戶不在”
客戶名:yangry
city:henan+
---創建表 create table customer(customer_id number not null,customer_name varchar2(50), city_name varchar2(50) ,constraint pk_customer primary key(customer_id)); ---代碼 set serveroutput on; declare v_name customer.customer_name%type; v_city customer.city_name%type; begin v_name := '&customer_name'; v_city := '&city_name'; update customer set city_name=v_city where upper(customer_name)=upper(v_name); if sql%notfound then dbms_output.put_line('customer is not exist.'); end if; commit; end;
三.PL/SQL集合
(1)索引表(Associative arrays, also known as index-by tables)
(2)嵌套表
(3)變長數組
用於處理多行單列數據
(4)PL/SQL記錄表
處理多行多列數據
1.pl/sql記錄
TYPE type_name IS RECORD(
field_declaration1[,field_declaration2]...
);
identifier type_name;
type_name:記錄類型的名稱(IS RECORD 表示記錄類型)
field_declaration:記錄成員的定義,多個記錄成員之間用逗號(,)隔開.
identifier:指定記錄變量名
定義pl/sql記錄方法1:
type emp_record_type is record (
names emp.ename%type,
salary emp.sal%type,
dno emp.deptno%type
);
---emp_record是基於記錄類型emp_record_type所定義的記錄變量
emp_record emp_record_type;
定義pl/sql記錄方法2:
%rowtype屬性可以基於表或者視圖定義記錄變量
identified table_name%rowtype;
or
identified view_name%rowtype;
dept_record dept%rowtype;
----ename,sal,dno
---替代變量用eno---empno
dbms_output.put_line(emp_record.names);
set serveroutput on; declare type emp_record_type is record( names emp.ename%type, salary emp.sal%type, dno emp.deptno%type ); emp_record emp_record_type; begin select ename,sal,deptno into emp_record from emp where empno=&no; dbms_output.put_line('names: ' || emp_record.names); dbms_output.put_line('salary: ' || emp_record.salary); dbms_output.put_line('dno: ' || emp_record.dno); end;
---在select into語句中使用記錄成員
set serveroutput on; declare type emp_record_type is record( names emp.ename%type, salary emp.sal%type, dno emp.deptno%type ); emp_record emp_record_type; begin select ename,sal,deptno into emp_record.names,emp_record.salary,emp_record.dno from emp where empno=&no; dbms_output.put_line('names: ' || emp_record.names); dbms_output.put_line('salary: ' || emp_record.salary); dbms_output.put_line('dno: ' || emp_record.dno); end;
---在insert的values子句中使用記錄變量/記錄成員,向dept表中插入一條數據
set serveroutput on; declare dept_record dept%rowtype; begin dept_record.deptno :=&no; dept_record.dname := &names; dept_record.loc :=&city; ---insert into dept(deptno,dname,loc) values(); insert into dept values dept_record; end;
2.嵌套表(nested table)
嵌套表一種用於處理PL/SQL數組的數據類型。嵌套表的元素下標從1開始,並且元素個數沒有限制。
語法:
table type_name is table of element_type;
identifier type_name;
type_name指嵌套表的類型名。
element_type指嵌套表元素的數據類型。
identifier指嵌套表變量。
使用嵌套表元素時,需要先使用構造方法初始化嵌套表
declare
table emp_table_type is table of emp.ename%type;
emp_table emp_table_type := emp_table_type('c','c');
//emp表中僱員姓名
set serveroutput on; declare type ename_table_type is table of emp.ename%type; ename_table ename_table_type; begin ename_table :=ename_table_type('y1','y2'); select ename into ename_table(1) from emp where empno=&no; dbms_output.put_line('employee name: ' || ename_table(1)); end;
3.集合方法
COUNT, DELETE, EXISTS, EXTEND, FIRST, LAST, LIMIT, NEXT, PRIOR, and TRIM
4.批量綁定
forall語法
forall index in lower_bound..upper_bound
sql_statement;
index隱含定義的×××變量(作爲集合元素下標使用)
lower_bound|upper_bound集合元素的上界和下界。
create table tmp01(id number primary key, name varchar(10));
---code
declare type id_table_type is table of number index by binary_integer; type name_table_type is table of varchar2(10) index by binary_integer; id_table id_table_type ; name_table name_table_type ; start_time number; end_time number; begin for i in 1..5000 loop id_table(i):=i; name_table(i):='name' || i; end loop; start_time := DBMS_UTILITY.GET_TIME; forall i in 1..5000 insert into tmp01 values(id_table(i),name_table(i)); commit; end_time := DBMS_UTILITY.GET_TIME; dbms_output.put_line('total time is: ' || to_char((end_time-start_time)/100)); end;
5.索引表
---語法
TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX BY key_type;
indentifer type_name;
type_name指定用戶自定義數據類型名稱
element_type 指定索引表元素的數據類型
key_type指定索引表元素下標的數據類型(varchar2,binary_integer,pls_integer等)
indentifer指定索引表變量
索引表的下標可以爲負值,而且元素個數沒有限制。
---code
set serveroutput on; declare type ename_table_type is table of emp.ename%type index by binary_integer; ename_table ename_table_type; begin select ename into ename_table(1) from emp where empno=&no; dbms_output.put_line('employee name : ' || ename_table(1)); end;
---索引表中使用varchar2
set serveroutput on; declare type city_table_type is table of number index by varchar2(10); city_table city_table_type; begin city_table('zhouzq') := 1; city_table('lidd') := 2; city_table('lijian') := 3; dbms_output.put_line('the first element: ' || city_table.first); dbms_output.put_line('the last element: ' || city_table.last); end;
6.遊標
使用顯示遊標包括定義遊標,打開遊標,提取遊標和關閉遊標。
(1)定義遊標
CURSOR cursor_name IS select_statement;
(2)打開遊標
OPEN cursor_name;
(3)提取遊標
---提取一行
FETCH cursor_name into var1,var2...;
---提取多行
FETCH cursor_name BULK COLLECT INTO collect1,collect2...[LIMIT rows];
---collect1用於指定接受遊標的集合變量
(4)關閉遊標
CLOSE cursor_name;
顯示遊標屬性:%isopen,%found,%notfound,%rowcount
---顯示遊標中使用fetch...into
//提取僱員名,薪水
set serveroutput on; declare cursor emp_cursor is select ename,sal from emp where deptno=10; v_ename emp.ename%type; v_salary emp.sal%type; begin open emp_cursor; loop fetch emp_cursor into v_ename,v_salary; exit when emp_cursor%notfound; dbms_output.put_line(v_ename || ' : ' || v_salary); end loop; end;
---顯示遊標中使用fetch...bulk collect into
###顯示部門10的所有僱員名
set serveroutput on; declare cursor ename_cursor is select ename from emp where deptno=10; type ename_table_type is table of varchar2(10); ename_table ename_table_type; begin open ename_cursor; fetch ename_cursor bulk collect into ename_table; for i in 1..ename_table.count loop dbms_output.put_line(ename_table(i)); end loop; close ename_cursor; end;
---遊標FOR循環
語法:
FOR record_name IN cursor_name loop
statement1;...
end loop;
cursor_name:已定義的遊標名稱
record_name:隱含定義的記錄變量名
在執行循環體內容之前,oracle會隱含地打開遊標,並且每循環一次提取一次數據,提取完所有數據後,會自動退出循環並隱含關閉遊標。
---FOR循環遊標
set serveroutput on; declare cursor ename_cursor is select ename from emp; begin for cc_record in ename_cursor loop dbms_output.put_line(ename_cursor%rowcount ||': ' || cc_record.ename); end loop; end;
---遊標FOR循環中直接使用子查詢
set serveroutput on; begin for cc_record in (select ename from emp) loop dbms_output.put_line( cc_record.ename); end loop; end;