oracle pl/sql之pl/sql語法

一.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;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章