<四> 游标
<1>、SQL SERVER端语法说明

1、DECLARE CURSOR语句

语法:

DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR

FOR select_statement

[FOR {READ ONLY | UPDATE [OF column_list ]}]

例:

DECLARE authors_cursor CURSOR FOR

SELECT au_lname, au_fname

FROM authors

WHERE au_lname LIKE ‘B%’

ORDER BY au_lname, au_fname


2、OPEN语句

语法:

OPEN cursor_name

例:

OPEN authors_cursor


3、FETCH语句

语法:

FETCH

[ [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n ]

FROM cursor_name

[INTO @variable_name1, @variable_name2,… ]

例:

FETCH NEXT FROM authors_cursor

INTO @au_lname, @au_fname


4、CLOSE语句

语法:

CLOSE cursor_name

例:

CLOSE authors_cursor


5、DEALLOCATE语句

语法:

DEALLOCATE cursor_name

例:

DEALLOCATE authors_cursor


6、游标中的标准循环与循环终止条件判断

(1)FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname


(2)-- Check @@FETCH_STATUS to see if there are any more rows to fetch.

WHILE @@FETCH_STATUS = 0

BEGIN

-- Concatenate and display the current values in the variables.

PRINT "Author: " + @au_fname + " " + @au_lname


-- This is executed as long as the previous fetch succeeds.

FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname

END


(3)CLOSE authors_cursor

7、隐式游标

MSSqlServer中对于数据操纵语句受影响的行数,有一个全局的变量:@@rowcount,其实它是一个隐式的游标,它记载了上条数据操纵语句所影响的行数,当@@rowcount小于1时,表时,上次没有找到相关的记录,如下:

Update students set lastname = ‘John’ where student_id = ‘301’

If @@rowcount < 1 then

Insert into students values (‘301’,’stdiv’,’john’,’996-03-02’)

表示如果数据表中有学号为“301”的记录,则修改其名字为“John”,如果找不到相应的记录,则向数据库中插入一条“John”的记录。

8、示例:

-- Declare the variables to store the values returned by FETCH.

DECLARE @au_lname varchar(40), @au_fname varchar(20)


DECLARE authors_cursor CURSOR FOR

SELECT au_lname, au_fname

FROM authors

WHERE au_lname LIKE ‘B%’

ORDER BY au_lname, au_fname


OPEN authors_cursor


-- Perform the first fetch and store the values in variables.

-- Note: The variables are in the same order as the columns

-- in the SELECT statement.


FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname


-- Check @@FETCH_STATUS to see if there are any more rows to fetch.

WHILE @@FETCH_STATUS = 0


BEGIN

-- Concatenate and display the current values in the variables.

PRINT "Author: " + @au_fname + " " + @au_lname


-- This is executed as long as the previous fetch succeeds.

FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname

END


CLOSE authors_cursor


DEALLOCATE authors_cursor


<2>、ORACLE端语法说明

1、 DECLARE CURSOR语句

语法:

CURSOR cursor_name IS select_statement;

例:

CURSOR authors_cursor IS

SELECT au_lname, au_fname

FROM authors

WHERE au_lname LIKE ‘B%’

ORDER BY au_lname, au_fname;


2、 OPEN语句

语法:

OPEN cursor_name

例:

OPEN authors_cursor;


3、 FETCH语句

语法:

FETCH cursor_name INTO variable_name1 [, variable_name2,… ] ;

例:

FETCH authors_cursor INTO au_lname, au_fname;


4、 CLOSE语句

语法:

CLOSE cursor_name

例:

CLOSE authors_cursor;


5、简单游标提取循环结构与循环终止条件判断

1> 用%FOUND做循环判断条件的WHILE循环

(1)FETCH authors_cursor INTO au_lname, au_fname ;

(2)WHILE authors_cursor%FOUND LOOP

-- Concatenate and display the current values in the variables.

DBMS_OUTPUT.ENABLE;

DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;

FETCH authors_cursor INTO au_lname, au_fname ;

END LOOP ;

(3)CLOSE authors_cursor ;


2> 用%NOTFOUND做循环判断条件的简单LOOP
END LOOP循环

(1)OPEN authors_cursor;

(2)LOOP

FETCH authors_cursor INTO au_lname, au_fname ;

-- Exit loop when there are no more rows to fetch.

EXIT WHEN authors_cursor%NOTFOUND ;

-- Concatenate and display the current values in the variables.

DBMS_OUTPUT.ENABLE;

DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;

END LOOP ;

(3)CLOSE authors_cursor ;

3>用游标式FOR循环,如下:

DECLARE

CURSOR c_HistoryStudents IS

SELECT id,first_name,last_name

FROM Students

WHERE major = ‘History’

BEGIN

FOR v_StudentData IN c_HistoryStudents LOOP

INSERT INTO registered_students

(student_id,first_name,last_name,department,course)

VALUES(v_StudentData.ID,v_StudentData.first_name, v_StudentData.last_name,’HIS’,301);

END LOOP;

COMMIT;

END;

首先,记录v_StudentData没有在块的声明部分进行声明,些变量的类型是c_HistoryStudents%ROWTYPE,v_StudentData的作用域仅限于此FOR循环本身;其实,c_HistoryStudents以隐含的方式被打开和提取数据,并被循环关闭。

6、隐式游标SQL%FOUND 与SQL%NOTFOUND

与MSSQL SERVER 一样,ORACLE也有隐式游标,它用于处理INSERT、DELETE和单行的SELECT..INTO语句。因为SQL游标是通过PL/SQL引擎打开和关闭的,所以OPEN、FETCH和CLOSE命令是无关的。但是游标属性可以被应用于SQL游标,如下:

BEGIN

UPDATE rooms

SET number_seats = 100

WHERE room_id = 9990;

--如果找不相应的记录,则插入新的记录

IF SQL%NOTFOUND THEN

INSERT INTO rooms(room_id,number_seats)

VALUES (9990,100)

END IF

END;

7、示例:

-- Declare the variables to store the values returned by FETCH.

-- Declare the CURSOR authors_cursor.

DECLARE

au_lname varchar2(40) ;

au_fname varchar2(20) ;

CURSOR authors_cursor IS

SELECT au_lname, au_fname

FROM authors

WHERE au_lname LIKE ‘B%’

ORDER BY au_lname, au_fname;


BEGIN

OPEN authors_cursor;

FETCH authors_cursor INTO au_lname, au_fname ;

WHILE authors_cursor%FOUND LOOP

-- Concatenate and display the current values in the variables.

DBMS_OUTPUT.ENABLE;

DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;

FETCH authors_cursor INTO au_lname, au_fname ;

END LOOP ;


CLOSE authors_cursor ;

END ;


<3>、从SQL SERVER向ORACLE的迁移方案

比较上述SQL代码,在迁移过程中要做如下调整:

(1)T-SQL对CURSOR的声明在主体代码中,而PL/SQL中对CURSOR的声明与变

量声明同步,都要在主体代码(BEGIN关键字)之前声明,所以在迁移时要

将游标声明提前,MSSQL SERVER的Cursor定义后的参数省去;

(2)对CUOSOR操作的语法中PL/SQL没有T-SQL里DEALLOCATE CURSOR这一部分,

迁移时要将该部分语句删除。

(3)PL/SQL 与T-SQL对游标中的循环与循环终止条件判断的处理不太一样,根

据前面的讨论并参考后面对两种语法集进行控制语句对比分析部分的叙述,

建议将T-SQL中的游标提取循环调整为PL/SQL中的WHILE游标提取循环结

构,这样可保持循环的基本结构大致不变,同时在进行循环终止条件判断时

要注意将T-SQL中的对@@FETCH_STATUS全局变量的判断调整为对

CURSOR_NAME%FOUND语句进行判断。

(4)对于T-SQL,没有定义语句结束标志,而PL/SQL用“;”结束语句。

(5)对于原MSSQL SERVER类型的游标,如果游标取出的值没有参与运算的,全部采用FOR循环方式来替换;而对于取出的值还要进行其它运算的,可以采用直接在定义变量位置定义变量。

(6)MSSQL中对于同一游标重复定义几次的情况在ORACLE中可通过游标变量来解决.如下:

MSSQL SERVER 中:

Declare cur_ypdm cursor for

Select * from yp

Open cur_yp

Fetch cur_yp into @yp,@mc …

While @@fetch_status <> -1

Begin

If @@fetch_status <> -2

Begin

….

End

Fetch cur_yp into @yp,@mc …

End

Close cur_ypdm

Deallocate cur_ypdm

..

Declare cur_ypdm cursor for

Select * from yp where condition 1

Open cur_yp

Fetch cur_yp into @yp,@mc …

While @@fetch_status <> -1

Begin

If @@fetch_status <> -2

Begin

….

End

Fetch cur_yp into @yp,@mc …

End

Close cur_ypdm

Deallocate cur_ypdm

..

Declare cur_ypdm cursor for

Select * from yp where condition 2

Open cur_yp

Fetch cur_yp into @yp,@mc …

While @@fetch_status <> -1

Begin

If @@fetch_status <> -2

Begin

….

End

Fetch cur_yp into @yp,@mc …

End

Close cur_ypdm

Deallocate cur_ypdm

..

在程序中,三次定义同一游标cur_yp

在迁移过程中,最好先定义一游标变量,在程序中用open打开,如下:

declare

type cur_type is ref cur_type;

cur_yp cur_type;

…

begin

open cur_yp for select * from yp;

loop

fetch cur_yp into yp,mc …

Exit When cur_yp%NotFound;

….

end loop;

close cur_yp;

open cur_yp for select * from yp where condition1;

loop

fetch cur_yp into yp,mc …

Exit When cur_yp%NotFound;

….

end loop;

close cur_yp;

open cur_yp for select * from yp where condition2;

loop

fetch cur_yp into yp,mc …

Exit When cur_yp%NotFound;

….

end loop;

close cur_yp;

end;

(7)请注意,游标循环中中一定要退出语名,要不然执行时会出现死循环。
posted on 2007-11-07 10:31
datasky 阅读(204)
评论(0) 编辑 收藏 网摘 所属分类:
Sql Server 、
Oracle