oracle中的cursor属性有哪些,Cursor语法及理解
游標(biāo)的兩種概念
共享游標(biāo)
:
是用戶提交
SQL
或
PL/SQL
程序塊到
Oracle
的
share pool
之后,在
library cache
中生成的一個(gè)可執(zhí)行對(duì)象,這個(gè)對(duì)象我們稱之為游標(biāo)(
cursor
)。是
SQL
語句在進(jìn)行硬解析時(shí)生成的,其元數(shù)據(jù)被在視圖
V$sqlarea
與
v$sql
中具體化。
PL/SQL
游標(biāo)
:
則是用于存放
SQL
語句的執(zhí)行結(jié)果
,
用戶可以通過這個(gè)中間緩沖區(qū)
逐條
取出游標(biāo)中的記錄并對(duì)其處理,直到所有的游標(biāo)記錄被逐一處理完畢。需要聲明、打開、提取、關(guān)閉。
共享游標(biāo)包括父游標(biāo)和子游標(biāo)。
父游標(biāo):
是在進(jìn)行硬解析時(shí)產(chǎn)生的。將
SQL
語句的文本進(jìn)行哈希得到哈希值并在
library cache
尋找相同的哈希值(
SQL
語句必須完全一致包括大小寫、空格回車等才能共享
),如不存在則生存父游標(biāo)且保存在
library cache
中,按順序完成后續(xù)步驟。如果此時(shí)存在父游標(biāo),則進(jìn)一步判斷是否存在子游標(biāo)。若存在相同的子游標(biāo),則直接調(diào)用其子游標(biāo)的執(zhí)行計(jì)劃執(zhí)行該
SQL
語句,否則轉(zhuǎn)到下一步進(jìn)行邏輯優(yōu)化。
子游標(biāo):
在發(fā)生硬解析時(shí),在產(chǎn)生父游標(biāo)的同時(shí),則跟隨父游標(biāo)會(huì)產(chǎn)生相應(yīng)的子游標(biāo),此時(shí)
V$SQL.CHILD_NUMBER
的值為
。如果存在父游標(biāo),由于不同的運(yùn)行環(huán)境,此時(shí)同樣會(huì)產(chǎn)生新的子游標(biāo),新子游標(biāo)的
CHILD_NUMBER
在已有子游標(biāo)基礎(chǔ)上以
1
為單位累計(jì)。
v$sql
中的每一行表示了一個(gè)
child cursor
子游標(biāo)
,根據(jù)
sql_id
與父
cursor
關(guān)聯(lián)。
child cursor
有自己的
address
,即
v$sql.child_address
。
如果你想確定是由那種原因造成的子游標(biāo),需要查看
v$sql_shared_cursor
。
1.
父游標(biāo)的關(guān)鍵信息是
sql
文本,子游標(biāo)的關(guān)鍵信息是執(zhí)行計(jì)劃和執(zhí)行環(huán)境。
2.
硬解析通常是由于不可共享的父游標(biāo)造成的,如經(jīng)常變動(dòng)的
SQL
語句,或動(dòng)態(tài)
SQL
或未使用綁定變量等。解決硬解析的辦法則通常是使用綁定變量來解決。
3.
與父游標(biāo)
SQL
文本完全一致的情形下,多個(gè)相同的
SQL
語句可以共享一個(gè)父游標(biāo)。
4.SQL
文本、執(zhí)行環(huán)境完全一致的情形下,子游標(biāo)能夠被共享,否則如果執(zhí)行環(huán)境不一致則生成新的子游標(biāo)。如果
SQL
文本相同,但是可能提交
SQL
語句的用戶不同,或者用戶提交的
SQL
語句所涉及到的對(duì)象為同名詞等,都有可能生成不同的子游標(biāo)。因?yàn)檫@些
SQL
語句的文本雖然完全一樣,但是上下文環(huán)境卻不一樣,因此這樣的
SQL
語句不是一個(gè)可執(zhí)行的對(duì)象,必須細(xì)化為多個(gè)子游標(biāo)后才能夠執(zhí)行。
5.
游標(biāo)是可以被所有進(jìn)程共享的,也就是說如果
100
個(gè)進(jìn)程都執(zhí)行相同的
SQL
語句,那么這
100
個(gè)進(jìn)程都可以同時(shí)使用該
SQL
語句所產(chǎn)生的游標(biāo),從而節(jié)省了內(nèi)存。
這里討論的游標(biāo)是指
pl/sql
語句中定義的游標(biāo)(
session cursor
)
。
Oracle
在
PL
/
SQL
中當(dāng)查詢返回結(jié)果超過一行時(shí),從中每次指向一條記錄進(jìn)行交互的話,就需要用到游標(biāo)。
例如:
SELECT
INTO
查詢語句,一次只能從數(shù)據(jù)庫(kù)中
select
一行數(shù)據(jù)來進(jìn)行
insert
,但是如果要處理多行數(shù)據(jù),就要由程序員定義一個(gè)顯式游標(biāo),并通過與游標(biāo)有關(guān)的語句進(jìn)行處理。
說明:
select
* into new_table from table;
在
sqlserver
中正常,但
oracle
會(huì)報(bào)錯(cuò),
在
oracle
里面
select...into...
是
pl/sql
的變量賦值語句
例如:
select
count(*) into v_count from table_name where id=1;
意思就是把
id=1
的數(shù)量放到一變量
v_count
中
當(dāng)然
insert into ?new_table? select * from table
都是在
sqlserver
或
oracle
中都是正常的,都可以一條
insert
語句插入多行數(shù)據(jù)
個(gè)人一般使用
for
m in (select * from emp)loop
來替代顯式游標(biāo)的功能
顯式游標(biāo)
(需要明確定義
cursor
,即有定義
cursor
的就是顯示游標(biāo))
fetch
游標(biāo)則必須用到顯式游標(biāo),需要
open
和
close
顯式游標(biāo)語法如下
declare
cursor mycursor1 is select * from emp;
--
聲明游標(biāo)
table_row mycursor1%rowtype;
--mycursor1%rowtype
表示數(shù)據(jù)類型是一行數(shù)據(jù)
xx number;
begin
open mycursor1;
--
打開游標(biāo)
loop
fetch mycursor1 into table_row;
--
取出游標(biāo)結(jié)果放入變量
table_row
exit when mycursor1%notfound;
xx:=table_row.empno;
insert into emp_2 (empno,ename,job ) values (xx,table_row.ename,table_row.job);
end loop;
commit;
close mycursor1;
--
關(guān)閉游標(biāo)
end;
如下顯式游標(biāo)
fetch
游標(biāo)名
into
變量
,
變量
,
變量,且變量不需要再定義為游標(biāo)名
%rowtype,
但是
sql
出現(xiàn)
游標(biāo)名
.
字段
則會(huì)報(bào)錯(cuò)
PLS-00225:
subprogram or cursor
'MYCURSOR111' reference is out of scope
declare
cursor mycursor111 is select empno,ename,job from emp;
--
聲明游標(biāo)
xx number;
yy varchar2(10);
zz varchar2(10);
begin
open mycursor111;
--
打開游標(biāo)
loop
fetch mycursor111 into xx,yy,zz;
--
取出游標(biāo)結(jié)果放入變量
xx,yy,zz
exit when mycursor111%notfound;
insert into emp_2 (empno,ename,job ) values (xx,yy,zz);
end loop;
commit;
close mycursor111;
--
關(guān)閉游標(biāo)
end;
顯示游標(biāo)
fetch
的注意事項(xiàng)
1.
游標(biāo)對(duì)應(yīng)的不管是一個(gè)還是多個(gè)字段,
fetch
游標(biāo)名
.
字段
into
變量,會(huì)報(bào)錯(cuò)
PLS-00225: subprogram or cursor
'MYCURSOR111' reference is out of scope
,但是可以出現(xiàn)
fetch
游標(biāo)名
into
字段
1
對(duì)應(yīng)的變量
1,
字段
2
對(duì)應(yīng)的變量
2,
字段
3
對(duì)應(yīng)的變量
3
,這里這些變量可以不需要定義為
%rowtype
,如果定義為
%rowtype
,則只能
into
一個(gè)
%rowtype
的變量,
fetch
游標(biāo)名
into
游標(biāo)名
%rowtype
2.
游標(biāo)對(duì)應(yīng)多個(gè)字段時(shí),
Fetch
游標(biāo)名
into
變量時(shí),其實(shí)是按順序把字段一個(gè)個(gè)
into
到變量的,如果游標(biāo)對(duì)應(yīng)的字段有
3
個(gè),但是
into
的變量只有
2
個(gè),則報(bào)錯(cuò)
PLS-00394:
wrong number of values in the INTO list of a FETCH statement
3.
游標(biāo)必須
open
,否則會(huì)報(bào)錯(cuò)
ORA-01001:
無效的游標(biāo)
,當(dāng)然如果沒有
close
的話執(zhí)行過程中不會(huì)報(bào)錯(cuò),但是游標(biāo)會(huì)一直存儲(chǔ)在
PAG
中,直到
session
關(guān)閉才會(huì)釋放,所以如果很多顯式都不關(guān)閉會(huì)導(dǎo)致
PGA
很大。
游標(biāo)
FOR
循環(huán)確實(shí)很好的簡(jiǎn)化了游標(biāo)的開發(fā),我們不在需要
open
、
fetch
和
close
語句,不在需要用
%FOUND
屬性檢測(cè)是否到最后一條記錄,這一切
Oracle
隱式的幫我們完成了。
(雖然是顯式游標(biāo),不過個(gè)人覺得更像隱式游標(biāo))
declare cursor mycursor1 is select * from emp;
--
聲明
cursor
vv varchar2(200);
begin
--open mycursor1;
--
這里
open
游標(biāo)反倒會(huì)報(bào)錯(cuò)
for m in mycursor1 loop
--m
不需要聲明
vv:=m.empno;
insert into emp_2 (empno,ename,job ) values (vv,m.ename,m.job);
end loop;
commit;
--close mycursor1;
--
這里
close
游標(biāo)反倒會(huì)報(bào)錯(cuò)
end;
下面語句只是比上面語句多了一行
xx
mycursor11%rowtype
,發(fā)現(xiàn)不需要這一行也一樣。
declare cursor mycursor11 is select * from emp;
--
聲明
cursor
xx mycursor11%rowtype;
yy varchar2(100);
begin
--open mycursor11;??????????????????????????????????? --
這里
open
游標(biāo)反倒會(huì)報(bào)錯(cuò)
for xx in mycursor11 loop
--m
不需要聲明
yy:=xx.empno;
insert into emp_2 (empno,ename,job ) values (yy,xx.ename,xx.job);
end loop;
commit;
--close mycursor11;???????????????????????????????? --
這里
close
游標(biāo)反倒會(huì)報(bào)錯(cuò)
end;
簡(jiǎn)單的
for
循環(huán)連
cursor
都不用聲明了,此時(shí)
m
不需要聲明類型,這是隱式游標(biāo)
create table emp_2 as select * from emp where 1=2
declare vv varchar2(200);
begin
for m in (select * from emp)loop
vv:=m.empno;
insert into emp_2 (empno,ename,job ) values (vv,m.ename,m.job);
end loop;
commit;
end;
相比如上,以下加了
sql%found
、
sql%rowcount
可以說明是隱式游標(biāo)
declare vv varchar2(200);
begin
for m in (select * from emp) loop
if
sql%found
then
dbms_output.put_line(
sql%rowcount
);
end if;
vv:=m.empno;
insert into emp_2 (empno,ename,job ) values (vv,m.ename,m.job);
end loop;
commit;
end;
隱式游標(biāo)
DECLARE
hid
VARCHAR2
(
10
);
hname
varchar
(
20
);
BEGIN
SELECT
empno
,
ename
INTO
hid
,
hname
FROM
emp_2
;
IF
SQL
%
FOUND
then
dbms_output.put_line
(
hid
||
'
的名字是
'
||
hname
);
end
if;
END;
則如下報(bào)錯(cuò),
select
into
只能有一行結(jié)果,加上
where
條件限定在一行后就不會(huì)報(bào)錯(cuò)了
ORA-01422:
實(shí)際返回的行數(shù)超出請(qǐng)求的行數(shù)
ORA-06512:
在
line 5
顯式游標(biāo)的個(gè)屬性
cursor_name%ISOPEN
游標(biāo)是否打開
cursor_name%FOUND
最近的
FETCH
是否提取到數(shù)據(jù)
cursor_name%NOTFOUND
最近的
FETCH
是否沒有提取到數(shù)據(jù)
cursor_name%ROWCOUNT
返回到目前為止,已經(jīng)從游標(biāo)緩沖區(qū)中提取到數(shù)據(jù)的行數(shù)
隱式游標(biāo)的屬性
SQL%ROWCOUNT
代表
DML
語句成功執(zhí)行的數(shù)據(jù)行數(shù)
SQL%FOUND
值為
TRUE
代表插入、刪除、更新或單行查詢操作成功
SQL%NOTFOUND
與
SQL%FOUND
屬性返回值相反
SQL%ISOPEN???????????? ???DML
執(zhí)行過程中為真,結(jié)束后為假
begin
for m in (select sign_id,SIGN_INFO_ID from MDS_SIGN_LIST)
loop
insert into MDS_SIGN_LIST_v2 (SIGN_ID,SIGN_INFO_ID )
values (m.sign_id,m.SIGN_INFO_ID);
end loop;
end;
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的oracle中的cursor属性有哪些,Cursor语法及理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 淘宝支付页面代码php,支付页面html
- 下一篇: 荆门 php,荆门php培训