青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Jiang's C++ Space

創作,也是一種學習的過程。

   :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::

[20060407發表于blog.csdn.net,20090929重新編輯]

重新編輯注釋:由于太久沒有使用PL/SQL,如今再看這篇筆記,幾乎完全陌生了,自己還到baidu去搜索了一下PL/SQL和Pro*C才依稀記起,我不知道以后還有沒有機會使用PL/SQL,但無疑的是這篇筆記還是有點價值的,或者作為一個紀念吧。PL/SQL(準確的寫法就是“PL/SQL”,沒有別的,不是Plus SQL,也不是SQL Plus)是Oracle對SQL的擴展,也就是說,PL/SQL只能用于Oracle,所以不要指望代碼能移植給MS SQL Server用,另外我印象比較深刻的是PL/SQL的語法很不嚴謹,bug比較多,用之前請三思,再有一點,這些代碼怎么用?就像C語言,要有編譯連接器生成可執行文件一樣,這些PL/SQL代碼也是需要編譯器的,不用說,它的編譯器一定是Oracle提供的,所以你得先安裝Oracle的客戶端,利用上面的調試工具調試。我以前是在Pro*C(在C代碼中嵌入PL/SQL,利用Oracle提供的預編譯生成C,然后才使用C的編譯器進行下去)中使用PL/SQL的。

程序不區分大小寫

1、SQL*Plus

SQL*Plus(Oracle客戶端提供)這個程序可以用來執行腳本,執行腳本前先設置假脫機文件,這樣就可以方便地查看出錯之處了。或者使用PL/SQL Developer的Command窗口來執行腳本。

2、代碼中變量的聲明

set serveroutput on;                      --設置輸出
DECLARE
    lv_ord_date DATE;                     
--日期類型
    lv_last_txt VARCHAR2(25):='Jiang';    --可變字符串類型,并初始化
    lv_qty_num CONSTANT NUMBER(2):=20;    --2位整數,常量,初始化
    lv_shipflag_bln BOOLEAN:=FALSE;       --布爾型,初始化為FALSE
    lv_name_txt CHAR(10NOT NULL:='CCC'--定長字符串類型,不能為空,初始化
BEGIN
    dbms_output.put_line (lv_qty_num);    
--這里一定要寫點什么東西才行
END;

3、簡單查詢

declare
    lv_basket_num 
number(3);
    lv_created_date date;
    lv_qty_num 
number(2);
    lv_sub_num 
number(5,2);
    lv_days_num 
number(3);
    lv_shopper_num 
number(3):=25;
begin
    
select idbasket, dtcreated, quantity, subtotal
    
into lv_basket_num, lv_created_date, lv_qty_num, lv_sub_num
    
from bb_basket
    
where idshopper = lv_shopper_num
        
and orderplaced = 0;
    lv_days_num:
=sysdate-lv_created_date;
    dbms_output.put_line(lv_basket_num
||' * '||lv_created_date
        
||' * '||lv_qty_num||' * '||lv_sub_num||' * '||lv_days_num);
end;

4、%type的使用

declare
    lv_basket_num bb_basket.idbasket
%type;   --與bb_basket.idbasket字段同類型
    lv_created_date bb_basket.dtcreated%type;
    lv_qty_num bb_basket.quantity
%type;
    lv_sub_num bb_basket.subtotal
%type;
    lv_days_num 
number(3);
begin
    
select idbasket, dtcreated, quantity, subtotal
    
into lv_basket_num, lv_created_date, lv_qty_num,lv_sub_num
    
from bb_basket
    
where idshopper=25
    
and orderplaced = 0;
    lv_days_num:
= sysdate-lv_created_date;
    dbms_output.put_line(lv_basket_num 
|| ' * ' ||
        lv_created_date 
|| ' * ' || lv_qty_num || ' * ' ||
        lv_sub_num 
|| ' * ' || lv_days_num);
end;

5、附加說明

要執行declare聲明的過程,需要使用“/”。而其它不需要。
在SQL*Plus窗口中直接鍵入“/”,表示執行最近declare的過程。

6、復合數據類型:RECORD

DECLARE 
    TYPE type_basket 
IS RECORD (
        basket bb_basket.idBasket
%TYPE,
        created bb_basket.dtcreated
%TYPE,
        qty bb_basket.quantity
%TYPE,
        sub bb_basket.subtotal
%TYPE);
    rec_basket type_basket;
    lv_days_num 
NUMBER(3);
    lv_shopper_num 
NUMBER(3) := 25;
BEGIN
    
SELECT idBasket, dtcreated, quantity, subtotal
    
INTO rec_basket
    
FROM bb_basket
    
WHERE idShopper = lv_shopper_num 
        
AND orderplaced = 0;
    lv_days_num :
= SYSDATE - rec_basket.created;
    DBMS_OUTPUT.PUT_LINE(rec_basket.basket);
    DBMS_OUTPUT.PUT_LINE(rec_basket.created);
    DBMS_OUTPUT.PUT_LINE(rec_basket.qty);
    DBMS_OUTPUT.PUT_LINE(rec_basket.sub);
    DBMS_OUTPUT.PUT_LINE(lv_days_num);
END;

7、復合數據類型:%ROWTYPE的使用

DECLARE 
    rec_shopper bb_shopper
%rowtype;
BEGIN
    
SELECT *
    
INTO rec_shopper
    
FROM bb_shopper
    
WHERE idShopper = 25;
    DBMS_OUTPUT.PUT_LINE(rec_shopper.lastname);
    DBMS_OUTPUT.PUT_LINE(rec_shopper.address);
    DBMS_OUTPUT.PUT_LINE(rec_shopper.email);
END;

“%rowtype”能根據表的結構自動創建rec_shopper這種數據類型,十分方便。

8、復合數據類型:記錄集

定義成“is table”就想當于一個記錄集,存在行數。
另外:聲明全局變量:

SQL>VARIABLE g_row NUMBER

注意,不需要“;”,也不需要“/”,使用變量的時候前面加上“:”。

variable g_row number
variable g_prod 
number
variable g_price 
number
variable g_qty 
number
variable g_opt1 
number
variable g_opt2 
number
begin
    :g_row :
= 1;
    :g_prod :
= 7;
    :g_price :
= 10.8;
    :g_qty :
= 2;
    :g_opt1 :
= 2;
    :g_opt2 :
= 3;
end;
/
 
declare
    type type_basketitem 
is table of bb_basketitem%rowtype
        
index by binary_integer;
    tbl_basketitems type_basketitem;
begin
    tbl_basketitems(:g_row).idproduct :
= :g_prod;
    tbl_basketitems(:g_row).price :
= :g_price;
    tbl_basketitems(:g_row).quantity :
= :g_qty;
    tbl_basketitems(:g_row).option1 :
= :g_opt1;
    tbl_basketitems(:g_row).option2 :
= :g_opt2;
    dbms_output.put_line(:g_row);
    :g_row :
= :g_row + 1;
    dbms_output.put_line(:g_row);
    dbms_output.put_line(:g_prod);
end;
/

9、隱式游標SQL%ROWCOUNT SQL%FOUND SQL%NOTFOUND

begin
    
update bb_product
    
set stock = stock + 25
    
where idProduct in (123);
    
if sql%notfound then
        dbms_output.put_line(
'Not found.');
    
end if;
    
if sql%found then
        dbms_output.put_line(
'Completed '||sql%rowcount||' rows.');
    
end if;
end;
/

10、游標的使用

variable g_basket number
begin
    :g_basket:
=6;
end;
/

declare
    
cursor cur_basket is
        
select bi.idbasket, p.type, bi.price, bi.quantity
        
from bb_basketitem bi inner join bb_product p on bi.idproduct=p.idproduct
        
where bi.idbasket = :g_basket;
    type type_basket 
is record
    (
        basket bb_basketitem.idbasket
%type,
        type bb_product.type
%type,
        price bb_basketitem.price
%type,
        qty bb_basketitem.quantity
%type
    );
    rec_basket type_basket;
    lv_rate_num 
number(2,2);
    lv_tax_num 
number(4,2):=0;
begin
    
open cur_basket;
    loop
        
fetch cur_basket into rec_basket;
        
exit when cur_basket%notfound;
        dbms_output.put_line(
'Every record:' || rec_basket.basket||' '||
            rec_basket.type
||' '||rec_basket.price||' '||rec_basket.qty);
        
if rec_basket.type = 'E' then
            lv_rate_num :
= .05;
        
end if;
        
if rec_basket.type = 'C' then
            lv_rate_num :
= .03;
        
end if;
        lv_tax_num :
= lv_tax_num +((rec_basket.price * rec_basket.qty) * 
            lv_rate_num);
    
end loop;
    
close cur_basket;
    dbms_output.put_line(lv_tax_num);
end;
/

游標除了上面的直接使用loop...end loop與fetch的結合來使用記錄集之外,還有下面的方式:

declare
    
cursor cur_prod is
        
select type, price
        
from bb_product
        
where active=1
        
for update nowait; 
        
--另一會話已經鎖定了游標正在檢索的行時,不必等待,繼續往下。
        --另外可寫成:for update of type, price nowait;指定鎖定的列。
    lv_sale bb_product.saleprice%type;
begin
    
for rec_prod in cur_prod loop
        
if rec_prod.type = 'C' then
            lv_sale:
=rec_prod.price * 0.8;
        
end if;
        
if rec_prod.type = 'E' then
            lv_sale :
= rec_prod.price * 0.85;
        
end if;
        
update bb_product
            
set saleprice = lv_sale
            
where current of cur_prod;
        
--dbms_output.put_line('Updated record:' || sql%rowcount);
    end loop;
    
commit;
end;

上面兩個例子都是在declare中聲明并定義游標,下面的例子則是:仍然在declare中聲明,但是定義放在begin...end中。

declare
    type type_curvar 
is ref cursor;
    cv_prod type_curvar;
    rec_basket bb_basket
%rowtype;
    rec_shipping bb_shipping
%rowtype;
begin
    dbms_output.put_line(
'################ bb_basket ################');
    
open cv_prod for select * from bb_basket;
    loop
        
fetch cv_prod into rec_basket;
        
exit when cv_prod%notfound;
        dbms_output.put_line(rec_basket.idbasket 
|| ' ' || 
            rec_basket.quantity 
|| ' ' || rec_basket.idshopper || ' ' || 
            rec_basket.orderplaced);
    
end loop;
    dbms_output.put_line(
'############### bb_shipping ###############');
    
open cv_prod for select * from bb_shipping;
    loop
        
fetch cv_prod into rec_shipping;
        
exit when cv_prod%notfound;
        dbms_output.put_line(rec_shipping.idrange 
|| ' ' || 
            rec_shipping.low 
|| ' ' || rec_shipping.high || ' ' || 
            rec_shipping.fee);
    
end loop;
end;

關于游標的,講了好多啊……沒辦法,游標就是很重要的概念。

11、變量定義與范圍示例

declare
    lv_one 
number(2):=10;
    lv_two 
number(2):=20;
begin
    
declare
        lv_one 
number(2):=30;
        lv_three 
number(2):=40;
    
begin
        lv_one:
=lv_one+10;
        lv_two:
=lv_two+10;
        dbms_output.put_line(
'Nested lv_one='||lv_one);
        dbms_output.put_line(
'Nested lv_two='||lv_two);
        dbms_output.put_line(
'Nested lv_three='||lv_three);
    
end;
    lv_one:
=lv_one+10;
    lv_two:
=lv_two+10;
    dbms_output.put_line(
'Enclosing lv_one='||lv_one);
    dbms_output.put_line(
'Enclosing lv_two='||lv_two);
end;

塊頭declare處定義的變量只在當塊中生效。如果塊頭沒有定義,但塊體中使用了,程序就把變量當作外部變量。

12、if/elsif語句

非常有意思,這里用的不是elseif,而是elsif,千萬別寫錯了。

declare
    type type_order 
is record(
        basket bb_basket.idbasket
%type,
        sub bb_basket.subtotal
%type,
        state bb_basket.shipstate
%type);
    rec_order type_order;
    lv_tax_num 
number(4,2):=0;
begin
    
select idbasket, subtotal, shipstate
        
into rec_order
        
from bb_basket
        
where idbasket=6;
    
if rec_order.state='VA' then
        lv_tax_num:
=rec_order.sub*0.06;
    elsif rec_order.state
='ME' then
        lv_tax_num:
=rec_order.sub*0.05;
    elsif rec_order.state
='NY' then
        lv_tax_num:
=rec_order.sub*0.07;
    
else
        lv_tax_num:
=rec_order.sub*0.04;
    
end if;
    dbms_output.put_line(
'State='||rec_order.state);
    dbms_output.put_line(
'Subtotal='||rec_order.sub);
    dbms_output.put_line(
'Tax amount='||lv_tax_num);
end;

if語句也可以使用or,and,in等運算符。例子這里就不舉了。

13、循環 loop,for,while

理所當然了,講完分支就講循環,一般的高級語言都這樣的。

declare
    lv_cnt_num 
number(2):=1;
begin
    loop
        dbms_output.put_line(lv_cnt_num);
        
exit when lv_cnt_num>5;
        lv_cnt_num:
=lv_cnt_num+1;
    
end loop;
end;

上面的范例是最簡單的loop循環。還可以參照游標的使用這一部分,也使用到了循環。

begin
    
for i in 1..5 loop
        dbms_output.put_line(i);
    
end loop;
end;

上面范例是最簡單的for循環。還可以參照游標這部分,有類似循環的使用。

declare
    lv_cnt_num 
number(2):=1;
begin
    
while lv_cnt_num<=5 loop
        dbms_output.put_line(lv_cnt_num);
        lv_cnt_num:
=lv_cnt_num+1;
    
end loop;
end;

使用while循環……

14、goto語句

說實在,對goto語句還是有點感情的。因為我最早接觸電腦的時候,認為電腦就是BASIC。

variable lv_rows_num number

begin
    :lv_rows_num:
=0;
    
    
if :lv_rows_num=0 then
        
goto insert_row;
    
end if;
    
    dbms_output.put_line(
'test point 1');
    
<<insert_row>>
    dbms_output.put_line(
'test point 2');
end;

15、意外處理

相當于VB中的on error goto ...之類的。下面是范例:

declare
    type type_basket 
is record(
        basket bb_basket.idbasket
%type,
        created bb_basket.dtcreated
%type,
        qty bb_basket.quantity
%type,
        sub bb_basket.subtotal
%type);
    rec_basket type_basket;
    lv_days_num 
number(3);
    lv_shopper_num 
number(3):=22;
begin
    
select idbasket, dtcreated, quantity, subtotal
        
into rec_basket
        
from bb_basket
        
where idshopper = lv_shopper_num and orderplaced = 0;
    lv_days_num :
= sysdate - rec_basket.created;
    dbms_output.put_line(rec_basket.basket);
    dbms_output.put_line(rec_basket.created);
    dbms_output.put_line(rec_basket.qty);
    dbms_output.put_line(rec_basket.sub);
    dbms_output.put_line(lv_days_num);
exception
    
when no_data_found then
        dbms_output.put_line(
'You have no saved baskets!');
    
when too_many_rows then
        dbms_output.put_line(
'You don't have enough space!');
end;

像上面的出錯標志no_data_found和too_many_rows是已經定義好的,常見的幾種出錯是:
NO_DATA_FOUND,TOO_MANY_ROWS,ZERO_DIVIDE,DUP_VAL_ON_INDEX(違反唯一性約束或主鍵約束)。如果非預定義Oracle錯誤,得參照下面的例子:

declare
    ex_basket_fk exception;
    pragma exception_init(ex_basket_fk, 
-2292);
begin
    
delete from bb_basket where idbasket=4;
exception
    
when ex_basket_fk then
        dbms_output.put_line(
'Items still in the basket!');
end;

關于出錯信息:ORA-02292:integrity constraint violated - child record found。

如果需要手動拋出錯誤,得參照下面的例子:

declare
    ex_prod_update exception;
begin
    
update bb_product
        
set description = 'NO NO NO NO'
        
where idproduct = 30;
    
if sql%notfound then
        raise ex_prod_update;
    
end if;
exception
    
when ex_prod_update then
        dbms_output.put_line(
'Invalid product id entered.');
end;

手動拋出錯誤的條件不僅僅是sql%notfound、sql%found和sql%rowcount幾個,條件可以是多方面的。如下例:

declare
    lv_ordqty_num 
number(2):=99;
    lv_stock_num 
number(4);
    ex_prod_stk exception;
begin
    
select stock
        
into lv_stock_num
        
from bb_product
        
where idproduct=2;
    
if lv_stock_num<lv_ordqty_num then
        raise ex_prod_stk;
    
end if;
exception
    
when ex_prod_stk then
    dbms_output.put_line(
'request quantity beyond stock level.');
end;

下面的例子說明內部塊的錯誤如果在塊內無法解決的話將傳遞到塊外解決。另外還說明了出錯代碼和出錯信息的獲取。

declare
    lv_junk1_num 
number(3):=200;
begin
    
declare
        lv_junk2_num 
number(3);
    
begin
        lv_junk2_num:
='cat';  --引發錯誤1
    exception
        
when others then
            lv_junk2_num:
='hat';  --引發錯誤2
            dbms_output.put_line('handler in nested block');
            dbms_output.put_line(
'Error code =' || sqlcode);  --錯誤碼
            dbms_output.put_line('Error message =' || sqlerrm);  --錯誤信息
    end;
    lv_junk1_num:
=300;
exception
    
when others then
        dbms_output.put_line(
'handler in outer block');
        dbms_output.put_line(
'Error code =' || sqlcode);  --錯誤碼
        dbms_output.put_line('Error message =' || sqlerrm);  --錯誤信息
end;

16、過程(Procedure)

過程可以保存起來,類似函數(除了沒有返回值),能供別處調用。下面是簡單示例:

create or replace procedure ship_cost_sp
(p_qty 
in number, p_ship out number)
is
begin
    
if p_qty>10 then
        p_ship:
=11.00;
    elsif p_qty
>5 then
        p_ship:
=8.00;
    
else
        p_ship:
=5.00;
    
end if;
end;
/
 
variable g_ship 
number;
 
execute ship_cost_sp(7, :g_ship);
begin
    dbms_output.put_line(
'Now g_ship is '|| :g_ship);
end;
/

上面的例子是用命令方式來調用過程。下面的例子將說明如何使用過程來調用過程。

create or replace procedure order_total_sp
(p_bsktid 
in number,p_cnt out number, p_sub out number,p_ship out number, p_total out number)
is
begin
    
select sum(quantity), sum(quantity*price)
        
into p_cnt, p_sub
        
from bb_basketitem
        
where idbasket=p_bsktid;
        ship_cost_sp(p_cnt, p_ship);  
--過程調用過程
        p_total :=nvl(p_sub,0)+nvl(p_ship, 0);
end;
/
 
variable g_cnt 
number
variable g_sub 
number
variable g_ship 
number
variable g_total 
number
 
execute order_total_sp(12, :g_cnt, :g_sub, :g_ship, :g_total);
 
print :g_cnt
print :g_sub
print :g_ship
print :g_total

這個例子除了說明如何用過程調用過程之外,還教了“print”命令,用來打印單個變量的值,調試的時候非常有用。
另外發現個有意思的現象,過程定義的時候不需要使用declare關鍵字,使用了也沒錯,但會產生warning,不好的。

17、復雜度進一步的過程

仔細閱讀下面的例子:

create or replace procedure promo_test_sp
(p_mth 
in char, p_year in char)
is
cursor cur_purch is
    
select idshopper, sum(subtotal) sub
        
from bb_basket
        
where to_char(dtcreated, 'MM')=p_mth
            
and to_char(dtcreated, 'YYYY')=p_year
            
and orderplaced=1
        
group by idshopper;
    promo_flag 
char(1);
begin
    
for rec_purch in cur_purch loop
        
if rec_purch.sub>50 then
            promo_flag:
='A';
        elsif rec_purch.sub
>25 then
            promo_flag:
='B';
        
end if;
        
        
if promo_flag is not null then
            
insert into bb_promolist
                
values(rec_purch.idshopper, p_mth, p_year, promo_flag, null);
        
end if;
        promo_flag:
=null;
    
end loop;
    
commit;
end;
/
execute promo_test_sp ('02''2003');

這個例子和上個例子其實沒有本質的區別。但注意紅色字部分,原本是寫成“promo_flag:=''”的形式,事實上,null并不等于“''”,這個千萬要注意,否則得不到正確的結果。

18、刪除過程

一句話,沒什么好說的了。
drop procedure procedure_name;

19、函數

其實和過程沒什么區別,就像VB,區別就在于一個有返回值,一個沒有。
當然,例子很重要,先舉個例子啦。

create or replace function ship_calc_sf
(p_qty 
in number)    --函數同樣有輸入輸出參數
return number
is
    lv_ship_num 
number(5,2);
begin
    
if p_qty > 10 then
        lv_ship_num :
= 11.00;
    elsif p_qty
>5 then
        lv_ship_num:
=8.00;
    
else
        lv_ship_num:
=5.00;
    
end if;
    
return lv_ship_num;
end;
/

函數的使用方法,如下:

select idbasket, shipping actual, ship_calc_sf(quantity) calc, 
    ship_calc_sf(quantity)
-shipping diff
from bb_basket
where orderplaced =1;

在函數中使用函數的示例:

create or replace function memfmt1_sf(
    p_id 
in number,
    p_first 
in varchar2,
    p_last 
in varchar2)
return varchar2
is
    lv_mem_txt 
varchar2(35);
begin
    lv_mem_txt:
='Member '||p_id||'-'||p_first||' '||p_last;
    
return lv_mem_txt;
end;
/
declare
    lv_name_txt 
varchar2(35);
    lv_id_num 
number(4):=25;
    lv_first_txt 
varchar2(15):='Scott';
    lv_last_txt 
varchar2(20):='Savid';
begin
    lv_name_txt:
=memfmt1_sf(lv_id_num, lv_first_txt, lv_last_txt);
    dbms_output.put_line(lv_name_txt);
end;
/

上面例子很簡單,就不必多說了。
在過程中調用函數,順便復習一下“過程”吧。

create or replace procedure login2_sp(
    p_user 
in varchar2,
    p_pass 
in varchar2,
    p_id out 
number,
    p_flag out 
char,
    p_mem out 
varchar2)
is
    lv_first_txt bb_shopper.firstname
%type;
    lv_last_txt bb_shopper.lastname
%type;
begin
    p_flag :
= 'N';
    
select idshopper, firstname, lastname
        
into p_id, lv_first_txt, lv_last_txt
        
from bb_shopper
        
where username=p_user and password=p_pass;
    
if sql%notfound then
        
return;
    
else
        p_flag:
='Y';
        p_mem:
=memfmt1_sf(p_id, lv_first_txt, lv_last_txt);
    
end if;
end;

20、刪除函數

呵呵,同理的。
drop function function_name;

21、軟件包入門

軟件包,我理解成過程與函數的集合。下面是簡單范例。

CREATE OR REPLACE PACKAGE ordering_pkg
IS
    pv_total_num 
NUMBER(3,2);
PROCEDURE order_total_pp
    (p_bsktid 
IN NUMBER,
    p_cnt OUT 
NUMBER,
    p_sub OUT 
NUMBER,
    p_ship OUT 
NUMBER,
    p_total OUT 
NUMBER);
FUNCTION ship_calc_pf
    (p_qty 
IN NUMBER)
RETURN NUMBER;
END;
/
 
CREATE OR REPLACE PACKAGE BODY ordering_pkg IS
 
FUNCTION ship_calc_pf  
    (p_qty 
IN NUMBER)
    
RETURN NUMBER
IS
    lv_ship_num 
NUMBER(5,2);
BEGIN
    
IF p_qty > 10 THEN
        lv_ship_num :
= 11.00;
    ELSIF p_qty 
> 5 THEN
        lv_ship_num :
= 8.00;
    
ELSE
        lv_ship_num :
= 5.00;
    
END IF;
    
RETURN lv_ship_num;
END ship_calc_pf;
 
PROCEDURE order_total_pp
    (p_bsktid 
IN NUMBER,
    p_cnt OUT 
NUMBER,
    p_sub OUT 
NUMBER,
    p_ship OUT 
NUMBER,
    p_total OUT 
NUMBER)
IS
BEGIN
    
SELECT SUM(quantity),SUM(quantity*price)
    
INTO p_cnt, p_sub
    
FROM bb_basketitem
    
WHERE idbasket = p_bsktid;
        p_ship :
= ship_calc_pf(p_cnt);
        p_total :
= NVL(p_sub,0+ NVL(p_ship,0);
END order_total_pp;
 
END;
/

執行完以上代碼之后,就能生成了ordering_pkg的軟件包。下面的操作用來測試軟件包:

variable cnt number
variable sub 
number
variable ship 
number
variable total 
number
execute ordering_pkg.order_total_pp(12, :cnt, :sub, :ship, :total);

22、觸發器

初步了解到觸發器的觸發條件是:使用insert、update或delete對某個表進行操作。簡單范例如下:

CREATE OR REPLACE TRIGGER product_inventory_trg
    AFTER 
UPDATE OF orderplaced ON bb_basket
    
FOR EACH ROW
    
WHEN (OLD.orderplaced <> 1 AND NEW.orderplaced = 1)
DECLARE
    
CURSOR basketitem_cur IS
        
SELECT idproduct, quantity, option1
            
FROM bb_basketitem
            
WHERE idbasket = :NEW.idbasket;
    lv_chg_num 
NUMBER(3,1);
BEGIN
    
FOR basketitem_rec IN basketitem_cur LOOP
        
IF basketitem_rec.option1 = 1 THEN
            lv_chg_num :
= (.5 * basketitem_rec.quantity);
        
ELSE
            lv_chg_num :
= basketitem_rec.quantity;
        
END IF;
        
UPDATE bb_product
            
SET stock = stock - lv_chg_num
            
WHERE idproduct = basketitem_rec.idproduct;
    
END LOOP;
END;
/

“AFTER UPDATE OF orderplaced ON bb_basket”為主觸發條件,“WHEN (OLD.orderplaced <> 1 AND NEW.orderplaced = 1)”為附加條件,條件都成立后,才能觸發。OLD為事件發生前的相關記錄,NEW為事件發生后的相關記錄。測試的時候,試圖把bb_basket表中的某條記錄的orderplaced字段由0至成1,然后觀察表bb_product。
下面的例子說明多條件觸發,和條件謂詞判斷:

create or replace trigger product_inventory_trg
    after 
delete or update on bb_basket
    
for each row
declare
    
cursor basketitem_cur is
        
select idproduct, quantity
            
from bb_basketitem
            
where idbasket=:new.idbasket;
begin
    
if updating then
        
for basketitem_rec in basketitem_cur loop
        
update bb_product
            
set stock = stock - basketitem_rec.quantity
            
where idproduct = basketitem_rec.idproduct;
        
end loop;
    
end if;
    
    
if deleting then
        
for basketitem_rec in basketitem_cur loop
        
update bb_product
            
set stock = stock + basketitem_rec.quantity
            
where idproduct=basketitem_rec.idproduct;
        
end loop;
    
end if;
end;

23、“instead of”觸發器

利用instead of觸發器可以將特定的常規操作取代為相應的DML語句。

create or replace trigger jgg_trg
    instead 
of update on view_jgg
    
for each row
begin
    
update bb_basket
        
set orderplaced = :new.orderplaced
        
where idbasket = :new.idbasket;
    
insert into bb_basketstatus
        
values(553'15-2月-03''JGG'null,null);
end;

“instead of xxx on yyy”中的yyy只能是視圖,不能是表。建立了上面這么個觸發器,如果對view_jgg執行update操作的時候,就會取而代之地執行begin...end之間的語句。

posted on 2009-09-29 13:32 Jiang Guogang 閱讀(973) 評論(0)  編輯 收藏 引用 所屬分類: Knowledge
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品久久久久9999高清| 一区二区三区国产精华| 欧美一级黄色网| 国产精品综合色区在线观看| 午夜在线成人av| 午夜精品久久久久久久99热浪潮| 国产伦精品一区二区三区高清版| 久久精品亚洲| 噜噜噜在线观看免费视频日韩| 亚洲黄色影片| 妖精视频成人观看www| 国产精品美女久久福利网站| 久久久精品国产一区二区三区| 午夜亚洲一区| 亚洲精品激情| 99国产成+人+综合+亚洲欧美| 欧美性大战久久久久| 久久成人一区| 欧美国产极速在线| 亚洲免费在线精品一区| 久久精彩免费视频| 一区二区三区 在线观看视频| 亚洲欧美日韩久久精品| 亚洲国产日韩一区| 99热在这里有精品免费| 国内精品视频一区| 亚洲看片一区| 国产一在线精品一区在线观看| 亚洲电影免费观看高清完整版在线观看 | 日韩午夜在线观看视频| 亚洲与欧洲av电影| 亚洲精品乱码久久久久久蜜桃麻豆 | 一区二区欧美日韩视频| 亚洲欧美日韩国产成人| 最新中文字幕一区二区三区| 亚洲永久免费| 99精品黄色片免费大全| 久久黄色网页| 欧美在线综合视频| 欧美日韩精品在线播放| 欧美不卡视频| 国产亚洲福利| 一区二区高清| 日韩视频专区| 米奇777超碰欧美日韩亚洲| 午夜在线视频观看日韩17c| 欧美电影资源| 欧美风情在线观看| 海角社区69精品视频| 亚洲一区二区三区四区在线观看| 亚洲美女毛片| 欧美激情第8页| 欧美成人精精品一区二区频| 国产亚洲在线| 欧美在线视频一区| 欧美影院在线播放| 国产精品国产a级| 99成人精品| 亚洲一区久久久| 欧美日韩在线高清| 亚洲伦理一区| 亚洲视频精品| 国产精品国产三级国产普通话蜜臀| 亚洲激情电影在线| 日韩一本二本av| 欧美日韩精品三区| 日韩视频一区| 亚洲主播在线播放| 国产精品视频| 久久国产精品一区二区三区四区| 欧美在线三区| 激情成人av| 麻豆91精品91久久久的内涵| 欧美国产日韩二区| 亚洲精品在线观看视频| 欧美欧美天天天天操| 99在线|亚洲一区二区| 亚洲特黄一级片| 国产视频观看一区| 久久久亚洲欧洲日产国码αv| 老鸭窝毛片一区二区三区| 亚洲国产精品va在线看黑人| 欧美国产激情| 亚洲欧美国产一区二区三区| 久久五月天婷婷| 亚洲日本视频| 国产精品你懂得| 久久精品中文字幕免费mv| 欧美大片一区| 亚洲永久视频| 在线观看亚洲精品| 欧美日韩午夜视频在线观看| 亚洲免费在线看| 欧美大片网址| 亚洲欧美日本伦理| 在线免费观看日本一区| 欧美日韩mv| 久久精品国产第一区二区三区最新章节| 欧美黑人一区二区三区| 久久国产精品久久久久久电车| 亚洲人成网站在线观看播放| 亚洲欧洲日本在线| 国产精品自在线| 欧美成人免费视频| 亚洲免费中文字幕| 亚洲国产成人久久| 久久se精品一区精品二区| 亚洲日本成人网| 国产婷婷色一区二区三区在线| 蜜臀av国产精品久久久久| 亚洲婷婷综合久久一本伊一区| 欧美成人福利视频| 欧美亚洲免费电影| 一本大道久久精品懂色aⅴ| 国产一区二区三区四区五区美女 | 亚洲高清免费| 国产精品视频导航| 欧美成人第一页| 久久久久久网| 欧美在线视频免费观看| 在线亚洲国产精品网站| 欧美激情片在线观看| 久久久噜噜噜久久狠狠50岁| 亚洲欧美国产精品桃花| 99国产精品自拍| 日韩性生活视频| 亚洲第一网站免费视频| 国产主播精品| 国产日韩在线一区| 国产精品入口夜色视频大尺度| 欧美精品一区二区三区蜜臀| 美女日韩欧美| 美女主播精品视频一二三四| 久久九九99视频| 午夜精品久久久久久久99水蜜桃| 亚洲小说欧美另类社区| 99国内精品久久| 99re在线精品| 99综合在线| 一本色道久久99精品综合| 99精品国产福利在线观看免费| 亚洲精品欧洲| 一本久久a久久免费精品不卡 | 欧美亚洲一区| 久久av在线| 久久久亚洲国产美女国产盗摄| 久久国产精品黑丝| 久久精彩视频| 久久综合一区| 欧美激情视频一区二区三区在线播放 | 日韩一级黄色av| 亚洲毛片一区二区| 日韩一区二区精品| 亚洲婷婷在线| 久久精品噜噜噜成人av农村| 久久久国产精品一区二区三区| 久久久国产精彩视频美女艺术照福利| 欧美freesex8一10精品| 亚洲欧美日韩综合国产aⅴ| 欧美在线一二三| 免费观看久久久4p| 欧美日韩一区二区欧美激情 | 欧美aⅴ一区二区三区视频| 欧美成在线观看| 欧美福利电影在线观看| 欧美日韩国产美女| 国产精品免费网站在线观看| 国产日产欧美精品| 黄色亚洲免费| 夜夜嗨av色综合久久久综合网| 亚洲欧美国产77777| 久久久www成人免费无遮挡大片 | 一区二区三区视频在线| 午夜视频一区在线观看| 美女啪啪无遮挡免费久久网站| 欧美精品尤物在线| 国产三级欧美三级| 亚洲欧洲精品成人久久奇米网| 国产精品99久久久久久www| 久久激情网站| 亚洲精品免费看| 欧美中文字幕不卡| 欧美理论在线| 精品盗摄一区二区三区| 在线视频你懂得一区| 久久视频国产精品免费视频在线| 亚洲日韩中文字幕在线播放| 亚洲女人天堂av| 欧美精品二区| 极品av少妇一区二区| 亚洲天堂激情| 欧美激情一区二区| 亚洲欧美日韩精品久久久久| 欧美黄色免费| 在线精品视频一区二区| 亚洲欧美日韩一区| 亚洲人体偷拍| 蜜桃av一区二区三区| 国产亚洲欧美激情| 亚洲一区二区三区在线视频|