日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小青蛙oracle跟踪,Oracle 存储过程:游标

發(fā)布時間:2024/9/27 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小青蛙oracle跟踪,Oracle 存储过程:游标 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、認識游標

什么是游標?游標是數據庫的一種數據類型,它用來管理從數據源(表,視圖等)獲取到的數據結果集,可以想象成一個游動的光標(指針),指向一個結果集,通過游標的移動逐行提取每一行的記錄,就像我們屏幕上的光標指示當前位置一樣,“游標”由此得名。

游標分成靜態(tài)游標和動態(tài)游標(也叫REF游標)。

靜態(tài)游標:所謂靜態(tài)游標,顧名思義,指的是數據已經固定的游標,在使用游標前,已經知道游標中的數據和類型。靜態(tài)游標又可以細分成顯式游標和隱式游標,顯示游標指的是已經定義在變量區(qū),并且已經指定結果集的游標;隱式游標則是不用定義,直接就可以用的游標,比如系統(tǒng)定義的隱式游標sql,比如使用for循環(huán)遍歷某個SQL(這個SQL的結果集就是一個隱式游標)的自定義游標。

動態(tài)游標:與靜態(tài)游標相反,在定義的時候并不知道其結果集,在使用時,再給它定義結果集(通俗來說,就是查詢數據的SQL不是一成不變的)的游標。動態(tài)游標也可以細分成強類型和弱類型游標,強類型游標規(guī)定了其返回類型,弱類型游標則是不規(guī)定返回類型,可以獲取任何結果集。

在使用游標時,通常需要借助游標的一些屬性來做邏輯判斷,比如說判斷游標是否已經到了結果集的尾部,這個時候可以使用游標的found屬性來做判斷:if 游標%found then 。。以下是游標的一些屬性具體說明:

1.%found?:用于檢驗游標是否成功,通常在fetch語句前使用,當游標按照條件查詢一條記錄是,返回true。fetch語句(獲取記錄)執(zhí)行情況True or False。

2.%notfound :?最后一條記錄是否提取出true or false。?到了游標尾部,沒有記錄了,就返回true

3.%isopen?: 游標是否打開true or false。

4.%rowcount?:游標當前提取的行數?,即獲得影響的行數。

二、游標使用的語法

1.靜態(tài)游標語法(顯式):

a.聲明游標:劃分存儲區(qū)域,注意此時并沒有執(zhí)行Select?語句:

CURSOR?游標名(參數 列表) ??[返回值類型]? ?is? select?語句;

b.打開游標:執(zhí)行select?語句,獲得結果集存儲到游標中,此時游標指向結果集頭部,類似于java的迭代器,必須先執(zhí)行.next(),游標才指向第一條記錄。

open?游標名(參數 列表);

c.獲取記錄:移動游標取一條記錄:

fetch ?游標名 into ?臨時記錄或屬性類型變量;

d.關閉游標:將游標放入緩沖池中,沒有完全釋放資源。可重新打開。

close ?游標名;

2.動態(tài)游標語法:

a.聲明REF游標類型:這個聲明相當于自定義一個游標類型,在聲明REF游標類型時,可以一并確定REF?游標的分類:

⑴強類型REF游標:指定retrun type,REF?游標變量的類型必須和return type一致。

語法:type ??REF游標名? ?is? ?ref cursor return ?結果集返回記錄類型;

⑵弱類型REF游標:不指定return type,能和任何類型的CURSOR變量匹配,用于獲取任何結果集。

語法:type ??REF游標名?is? ?ref cursor;

b.聲明REF游標類型變量:

語法:變量名??已聲明Ref游標類型;

c.打開REF游標,關聯(lián)結果集:

語法:open ??REF 游標類型變量 ??for ??查詢語句返回結果集;

d.獲取記錄,操作記錄:

語法:fetch ???REF游標名 into? ?臨時記錄類型變量或屬性類型變量列表;

e.關閉游標,完全釋放資源:

語法:close? ?REF游標名;

3.游標的遍歷:

a.for循環(huán)游標:使用for循環(huán)遍歷游標時,會自動打開游標,并且循環(huán)結束會自動關閉游標,所以在for循環(huán)之前和之后都不需要對游標進行open、close操作。另外,緊跟著for關鍵字的變量是不需要提前定義的。語法:

for 變量名 in 游標名

loop

處理邏輯;

end loop;

b.loop循環(huán)游標:? ?loop循環(huán)是不會自動打開或者關閉游標的,需要手動操作。退出循環(huán)語句必須在執(zhí)行邏輯操作之前執(zhí)行,原因是因為即使游標已經遍歷完,已經記錄游標變量的記錄是不會清除的,如果先執(zhí)行邏輯操作,會導致循環(huán)多走一次。語法:

open 游標名;

loop

fetch ?游標名 into ?臨時記錄或屬性類型變量(多個以逗號隔開);

exit ?when ??游標名%notfound;

邏輯操作

end ??loop;

close 游標名;

c.while循環(huán)游標:和loop有一點類似,語法:

open 游標名;

fetch ?游標名 into 臨時記錄或屬性類型變量(多個以逗號隔開);

while 游標名%found

loop

邏輯處理;

fetch ?游標名 into 臨時記錄或屬性類型變量(多個以逗號隔開);

end loop;

close?游標名;

三、示例

以下寫了兩個存儲過程,分別記錄了靜態(tài)游標和動態(tài)游標的基礎用法,可以用作參考:

靜態(tài)游標相關:

create or replace procedure test_static_cursor is

--無參數靜態(tài)顯式游標

-- return test_user%rowtype 這里的返回值可以要 也可以不要,因為后面的SQL已經指定了返回值

CURSOR static_cursor return test_user%rowtype is

select * /**u.id, u.username, u.password*/

from test_user u;

--帶參數的顯示游標 (參數名 參數類型 [default 默認值])

CURSOR static_cursor1(p_name test_user.id%type default '123') is

select * from test_user u where u.id = p_name;

--定義變量 這里的變量類型的意思是保持和test_user的id列的類型一致.

--在定義變量以獲取游標的數據時,建議使用這種方式

v_id test_user.id%type;

v_username test_user.username%type;

v_password varchar2(32);

--定義記錄(記錄的意思是游標的一條記錄)變量

v_record static_cursor1%rowtype;

v_num number;

begin

--初始化一些數據

delete from test_user;

commit;

select count(1) into v_num from test_user;

if v_num = 0 then

insert into test_user

(id, username, password)

values

('123', 'shaoyu', 'shaoyu');

--系統(tǒng)定義的隱式游標:SQL

--注意一句sql語句只會影響一個隱式游標,多個sql語句執(zhí)行會覆蓋隱式游標sql

if sql%found then

dbms_output.put_line('成功插入' || sql%rowcount || '條數據');

end if;

insert into test_user

(id, username, password)

values

('456', 'admin', 'admin');

insert into test_user

(id, username, password)

values

('789', 'system', 'system');

commit;

end if;

--打開游標,此時會執(zhí)行定義游標時的SQL

open static_cursor;

--讀取游標數據

fetch static_cursor

into v_id, v_username, v_password;

--驗證

dbms_output.put_line(v_id || '-' || v_username || '-' || v_password);

--關閉游標

close static_cursor;

--打開游標

open static_cursor1('456');

--讀取游標數據存入單個變量

fetch static_cursor1

into v_id, v_username, v_password;

--驗證

dbms_output.put_line(v_id || '-' || v_username || '-' || v_password);

close static_cursor1;

open static_cursor1('789');

--讀取游標數據存入記錄變量

fetch static_cursor1 into v_record ;

--驗證

dbms_output.put_line(v_record.id || '-' || v_record.username || '-' || v_record.password);

close static_cursor1;

--游標的遍歷:

--1.for循環(huán)(不需要打開游標)

dbms_output.put_line('for循環(huán)');

if static_cursor%isopen then

dbms_output.put_line('游標已打開');

else

dbms_output.put_line('游標未打開');

end if;

--data不需要提前定義

for data in static_cursor loop

if static_cursor%isopen then

dbms_output.put_line('游標已打開');

else

dbms_output.put_line('游標未打開');

end if;

dbms_output.put_line(data.id || '-' || data.username || '-' ||

data.password);

end loop;

if static_cursor%isopen then

dbms_output.put_line('游標已打開');

else

dbms_output.put_line('游標未打開');

end if;

--2.loop循環(huán)

dbms_output.put_line('loop循環(huán)');

open static_cursor;

loop

fetch static_cursor

into v_id, v_username, v_password;

exit when static_cursor%notfound;

dbms_output.put_line(v_id || '-' || v_username || '-' || v_password);

end loop;

close static_cursor;

--3.while循環(huán)

dbms_output.put_line('while循環(huán)');

open static_cursor;

fetch static_cursor

into v_id, v_username, v_password;

while static_cursor%found loop

dbms_output.put_line(v_id || '-' || v_username || '-' || v_password);

fetch static_cursor

into v_id, v_username, v_password;

end loop;

close static_cursor;

end test_static_cursor;

動態(tài)游標:

create or replace procedure test_dynamic_cursor is

--定義強類型REF游標類型

type dynamic_cursor_type1 is ref cursor return test_user%rowtype;

--定義弱類型REF游標

type dynamic_cursor_type2 is ref cursor;

--定義強類型REF自定義返回記錄類型游標類型 先定義自定義返回記錄類型 再定義游標類型

type dynamic_cursor_type3_rec is record(

user_id test_user.id%type,

username test_user.username%type);

type dynamic_cursor_type3 is ref cursor return dynamic_cursor_type3_rec;

--定義之前定義好的游標類型

dynamic_cursor1 dynamic_cursor_type1;

dynamic_cursor2 dynamic_cursor_type2;

dynamic_cursor3 dynamic_cursor_type3;

--定義返回類型變量

rec3 dynamic_cursor_type3_rec;

--定義變量

v_id test_user.id%type;

v_username test_user.username%type;

v_password varchar2(32);

v_num number;

begin

--初始化一些數據

delete from test_user;

commit;

select count(1) into v_num from test_user;

if v_num = 0 then

insert into test_user

(id, username, password)

values

('123', 'shaoyu', 'shaoyu');

insert into test_user

(id, username, password)

values

('456', 'admin', 'admin');

insert into test_user

(id, username, password)

values

('789', 'system', 'system');

commit;

end if;

dbms_output.put_line('強類型動態(tài)游標');

--給強類型動態(tài)游標關聯(lián)結果集

open dynamic_cursor1 for select * from test_user;

--驗證

loop

fetch dynamic_cursor1

into v_id, v_username, v_password;

exit when dynamic_cursor1%notfound;

dbms_output.put_line(v_id || '-' || v_username || '-' || v_password);

end loop;

close dynamic_cursor1;

--給弱類型動態(tài)游標關聯(lián)結果集

dbms_output.put_line('弱類型動態(tài)游標');

open dynamic_cursor2 for select id,password from test_user;

--驗證

loop

fetch dynamic_cursor2

into v_id, v_password;

exit when dynamic_cursor2%notfound;

dbms_output.put_line(v_id || '-' || v_password);

end loop;

close dynamic_cursor2;

--給自定義強類型動態(tài)游標關聯(lián)結果集

dbms_output.put_line('自定義返回類型強類型動態(tài)游標');

open dynamic_cursor3 for select id,username from test_user;

--驗證

loop

fetch dynamic_cursor3

into rec3;

exit when dynamic_cursor3%notfound;

dbms_output.put_line(rec3.user_id || '-' || rec3.username);

end loop;

close dynamic_cursor3;

end test_dynamic_cursor;

以上看起來游標好像就這么一些用法,那還有沒有別的用法呢?有的,那就是在使用游標時,對游標的結果集對應的數據源進行操作。

四、更新、刪除游標記錄

在定義游標的時候,如果在定義結果集的語句后面加上for update或者for delete子串,那么在使用游標時,就可以對游標的結果集進行操作,不要擔心數據源的狀態(tài),當使用for update、for delete子串打開一個游標時,所有返回集中的數據行都將處于行級(ROW-LEVEL)獨占式鎖定,其他對象只能查詢這些數據行,不能進行update、delete或select...for update操作,保證了數據的正確性。

值得提醒的是,在多表查詢中,使用of子句來鎖定特定的表,如果忽略了of子句,那么所有表中選擇的數據行都將被鎖定。如果這些數據行已經被其他會話鎖定,那么正常情況下oracle將等待,直到數據行解鎖。

語法:

a.聲明更新或刪除顯示游標:

cursor?游標名 is? select?語句 ??for update [ of ?更新列列名];

cursor?游標名 is? select?語句 ??for delete [ of ?更新列列名];

b.使用顯示游標當前記錄來更新或刪除:

update 表名 ??set 更新語句 ?where ??current ?of ??游標名;

delete from 表名 ?where ??current ?of ??游標名;

這個就不寫例子了,第三步的示例理解了之后,這個很容易編寫。

五、使用游標作為存儲過程出參

說了這么多,并沒有將游標應用到實際中,其實web程序對數據庫的調用多數情況下需要返回一個結果集,很顯然,游標是非常適合的。在這種情況下,只需要將游標作為存儲過程的出參就可以了。

1.包的概念

在上一篇中提到了包和存儲過程,那什么是包呢?包(package)也是數據庫的一種對象類型,它包含定義和包體(body)兩個方面,【定義】類似于是java中的接口,【包體】類似于是java中對接口的實現類,包里面是可以包含【自定義類型】和【存儲過程】的,可以認為是java接口中的全局變量(自定義類型)和方法(存儲過程),就連使用方式也極其類似:包名.存儲過程名(參數)。

有人覺得奇怪,不是要說游標做為存儲過程出參嗎?怎么又扯上包這個東西了?

在java中,所有的變量都有一個作用域,oracle數據庫也不例外,假設我們單獨定義一個存儲過程,在參數那一列是要規(guī)定參數類型的,如果我們使用的是自定義的游標,那么這個游標類型在這個存儲過程參數里是肯定沒有定義的,所以我們需要借助包,在包中定義自定義的游標類型,然后再把這個自定義游標作為包中的存儲過程的出入參,這樣就保證了游標在存儲過程中的作用域始終可用。

2.包的語法:

包定義:

create or replace package 包名 as

定義 自定義type

定義 全局變量

procedure 存儲過程名; --沒有存儲過程具體實現

function 函數名;

end test_package;

包體定義:

create or replace package body test_package as

定義變量

procedure 存儲過程名(參數) is ...存儲過程具體實現

end test_package;

下面寫個實例:

create or replace package test_package as

--定義游標類型

type o_cur is ref cursor;

--定義存儲過程

procedure test_static_cursor(o_data out o_cur);

end test_package;

create or replace package body test_package as

--存儲過程具體實現

procedure test_static_cursor(o_data out o_cur) is

v_num number;

begin

--初始化一些數據

delete from test_user;

commit;

select count(1) into v_num from test_user;

if v_num = 0 then

insert into test_user

(id, username, password)

values

('123', 'shaoyu', 'shaoyu');

insert into test_user

(id, username, password)

values

('456', 'admin', 'admin');

insert into test_user

(id, username, password)

values

('789', 'system', 'system');

commit;

end if;

--給出參關聯(lián)結果集

open o_data for

select * from test_user;

end;

end test_package;

總結

以上是生活随笔為你收集整理的小青蛙oracle跟踪,Oracle 存储过程:游标的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。