一 sqlserver遊標使用mysql
/*** 遊標的使用 講了這個多遊標的優勢,如今咱們就親自來揭開遊標的神祕的面紗。 使用遊標的順序: 聲名遊標、打開遊標、讀取數據、關閉遊標、刪除遊標。sql
1.3.1聲明遊標 最簡單遊標聲明:DECLARE <遊標名>CURSOR FOR<SELECT語句>;數據庫
其中select語句能夠是簡單查詢,也能夠是複雜的接連查詢和嵌套查詢 例子:函數
[已表2 AddSalary爲例子] Declare mycursor cursor for select * from AddSalary 這樣我就對錶AddSalary申明瞭一個遊標mycursoroop
【高級備註】 DECLARE <遊標名> [INSENSITIVE] [SCROLL] CURSORFOR<SELECT語句>sqlserver
這裏我說一下游標中級應用中的[INSENSITIVE]和[SCROLL] INSENSITIVE 代表MS SQL SERVER 會將遊標定義所選取出來的數據記錄存放在一臨時表內(創建在tempdb 數據庫下)。fetch
對該遊標的讀取操做皆由臨時表來應答。spa
所以,對基本表的修改並不影響遊標提取的數據,即遊標不會隨着基本表內容的改變而改變,同時也沒法經過遊標來更新基本表。若是不使用該保留字,那麼對基本表的更新、刪除都會反映到遊標中。 另外應該指出,當遇到如下狀況發生時,遊標將自動設定INSENSITIVE 選項。指針
a.在SELECT 語句中使用DISTINCT、 GROUP BY、 HAVING UNION 語句;code
b.使用OUTER JOIN;
c.所選取的任意表沒有索引;
d.將實數值看成選取的列。 SCROLL 代表全部的提取操做(如FIRST、 LAST、 PRIOR、 NEXT、 RELATIVE、 ABSOLUTE)均可用。若是不使用該保留字,那麼只能進行NEXT 提取操做。因而可知,SCROLL 極大地增長了提取數據的靈活性,能夠隨意讀取結果集中的任一行數據記錄,而沒必要關閉再 重開遊標。
1.3.2 打開遊標 很是簡單,咱們就打開剛纔咱們聲明的遊標mycursor OPEN mycursor
1.3.3讀取數據 FETCH [ NEXT | PRIOR | FIRST | LAST] FROM { 遊標名 | @遊標變量名 } [ INTO @變量名 [,…] ] 參數說明: NEXT 取下一行的數據,並把下一行做爲當前行(遞增)。因爲打開遊標後,行指針是指向該遊標第1行以前,因此第一次執行FETCH NEXT操做將取得遊標集中的第1行數據。NEXT爲默認的遊標提取選項。 INTO @變量名[,…] 把提取操做的列數據放到局部變量中。列表中的各個變量從左到右與遊標結果集中的相應列相關聯。各變量的數據類型必須與相應的結果列的數據類型匹配或是結果列數據類型所支持的隱性轉換。變量的數目必須與遊標選擇列表中的列的數目一致。 如今咱們就取出mycursor遊標的數據吧! 當遊標被打開時,行指針將指向該遊標集第1行以前,若是要讀取遊標集中的第1行數據,必須移動行指針使其指向第1行。就本例而言,可使用下列操做讀取第1行數據:
Eg: Fetch next from mycursor 或則 Fetch first from mycursor 這樣我就取出了遊標裏的數據,可是光光這樣可不夠,咱們還須要將取出的數據賦給變量
--聲明2個變量 declare @O_ID NVARCHAR(20)
declare @A_Salary float --將取出的值傳入剛纔聲明的2個變量
Fetch next from mycursor into @ O_ID,@ A_Salary
1.3.4關閉遊標 CLOSE mycursor
1.3.5刪除遊標 DEALLOCATE mycursor
1.3.6 實例訓練 **/ CREATE PROCEDURE PK_Test AS
--聲明2個變量
declare @O_ID nvarchar(20)
declare @A_Salary float --聲明一個遊標mycursor,select語句中參數的個數必需要和從遊標取出的變量名相同
declare mycursor cursor for select O_ID,A_Salary from AddSalary
--打開遊標
open mycursor
--從遊標裏取出數據賦值到咱們剛纔聲明的2個變量中
fetch next from mycursor into @O_ID,@A_Salary
--判斷遊標的狀態 -
- 0 fetch語句成功
---1 fetch語句失敗或此行不在結果集中
---2 被提取的行不存在
while (@@fetch_status=0) begin
--顯示出咱們每次用遊標取出的值
print '遊標成功取出一條數據'
print @O_ID
print @A_Salary
--用遊標去取下一條記錄
fetch next from mycursor into @O_ID,@A_Salary end -
-關閉遊標
close mycursor
--撤銷遊標
DEALLOCATE mycursor
GO -
---------------------------------------------------------------
create table testyoubiao(
id int not null primary key ,
names nvarchar(50),
address nvarchar(50)
)
select top 0 * into testyoubiao2 FROM testyoubiao
---testyoubiao表中有8條記錄
create PROCEDURE testpp
as
begin
declare @names nvarchar(20)
declare @address nvarchar(50)
declare mycursor cursor for select names,address from testyoubiao
--打開遊標
open mycursor
--從遊標裏取出數據賦值到咱們剛纔聲明的2個變量中
fetch next from mycursor into @names,@address
--while (@@fetch_status=0)
--begin
--顯示出咱們每次用遊標取出的值
print '1'
print @names
print @address
--用遊標去取下一條記錄
-- fetch mycursor into @names,@address
insert into testyoubiao2(names,address) values(@names,@address)
--end
--關閉遊標
close mycursor
--撤銷遊標
DEALLOCATE mycursor end
exec testpp
--這樣執行的結果testyoubiao2表只有一條記錄 就是說沒有循環就是隻去第一條
--fetch next from mycursor into @names,@address "next from"這個能夠不寫結果是同樣的
--------------------------------------------------------------------
create PROCEDURE testpp
as begin
declare @names nvarchar(20)
declare @address nvarchar(50)
declare mycursor cursor for select names,address from testyoubiao
--打開遊標
open mycursor
--從遊標裏取出數據賦值到咱們剛纔聲明的2個變量中
fetch next from mycursor into @names,@address
-- insert into testyoubiao2(names,address) values(@names,@address) 會增長一條數據與最後一條相同
while (@@fetch_status=0)
begin
--顯示出咱們每次用遊標取出的值
print '1'
print @names
print @address
--用遊標去取下一條記錄
fetch next from mycursor into @names,@address
insert into testyoubiao2(names,address) values(@names,@address)
end
--關閉遊標
close mycursor
--撤銷遊標
DEALLOCATE mycursor end
exec testpp
select * from testyoubiao2
truncate table testyoubiao2
drop PROCEDURE testpp
#----------------------------------------------------------------------
二 MySQL遊標使用
DELIMITER $$
create PROCEDURE testp16(in $id int )
BEGIN declare _uname varchar(20) ;
declare _uaddress VARCHAR(20);
DECLARE D_cursor CURSOR FOR select uname,uaddress from testa where id=$id;
OPEN D_cursor; FETCH NEXT FROM D_cursor into _uname, _uaddress;
CLOSE D_cursor;
insert into testd(uname,uaddress)values(_uname,_uaddress);
end;
-----------------------------------------------------------
DELIMITER $$
create PROCEDURE testp17()
BEGIN declare _uname varchar(20) ;
declare _uaddress VARCHAR(20);
declare couts int ;
declare i int default 0 ;
DECLARE D_cursor CURSOR FOR select uname,uaddress from testa;
set couts =(select count(id)from testa);
OPEN D_cursor;
-- FETCH NEXT FROM D_cursor into _uname, _uaddress;
-- insert into testd(uname,uaddress)values(_uname,_uaddress);這個地方加上這兩句數據時對的可是會有1329 錯誤提示
while i<couts DO -- 1329 - No data - zero rows fetched, selected, or processed 超出範圍了
FETCH NEXT FROM D_cursor into _uname, _uaddress;
insert into testd(uname,uaddress)values(_uname,_uaddress);
set i=1+i;
end while;
-- FETCH NEXT FROM D_cursor into _uname, _uaddress;
-- insert into testd(uname,uaddress)values(_uname,_uaddress);這個地方加上這兩句數據時對的可是會有1329 錯誤提示 CLOSE D_cursor; select i; end;
select * from testa
CALL testp17();--1329 - No data - zero rows fetched, selected, or processed 超出範圍了
CALL testp18()
select * from testd
TRUNCATE table testd
-----------------------------------------
/*爲下面的理解說明 定義條件和處理程序 定義條件和處理程序是事先定義程序執行過程當中可能遇到的問題。而且能夠在處理程序中定義解決這些問題的辦法。這種方式能夠提早預測可能出現的問題,並提出解決辦法。這樣能夠加強程序處理問題的能力,避免程序異常中止。MySQL中都是經過DECLARE關鍵字來定義條件和處理程序。
本小節中將詳細講解如何定義條件和處理程序。
1.定義條件 MySQL中可使用DECLARE關鍵字來定義條件。
其基本語法以下:
DECLARE condition_name CONDITION FOR condition_value condition_value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code
其中,condition_name參數表示條件的名稱;
condition_value參數表示條件的類型;sqlstate_value參數和mysql_error_code參數均可以表示MySQL的錯誤。
例如ERROR 1146 (42S02)中,sqlstate_value值是42S02,mysql_error_code值是1146。
【示例14-6】
下面定義"ERROR 1146 (42S02)"這個錯誤,名稱爲can_not_find。能夠用兩種不一樣的方法來定義,代碼以下:
//方法一:使用sqlstate_value DECLARE can_not_find CONDITION FOR SQLSTATE '42S02' ;
//方法二:使用mysql_error_code DECLARE can_not_find CONDITION FOR 1146 ; 2.定義處理程序
MySQL中可使用DECLARE關鍵字來定義處理程序。
其基本語法以下: DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement handler_type:
CONTINUE | EXIT | UNDO condition_value:
SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code
其中,handler_type參數指明錯誤的處理方式,該參數有3個取值。這3個取值分別是CONTINUE、EXIT和UNDO。CONTINUE表示遇到錯誤不進行處理,繼續向下執行;
EXIT表示遇到錯誤後立刻退出;UNDO表示遇到錯誤後撤回以前的操做,MySQL中暫時還不支持這種處理方式。
注意:一般狀況下,執行過程當中遇到錯誤應該馬上中止執行下面的語句,而且撤回前面的操做。
可是,MySQL中如今還不能支持UNDO操做。所以,遇到錯誤時最好執行EXIT操做。若是事先可以預測錯誤類型,而且進行相應的處理,那麼能夠執行CONTINUE操做。 condition_value參數指明錯誤類型,該參數有6個取值。sqlstate_value和mysql_error_code與條件定義中的是同一個意思。condition_name是DECLARE定義的條件名稱。SQLWARNING表示全部以01開頭的sqlstate_value值。NOT FOUND表示全部以02開頭的sqlstate_value值。SQLEXCEPTION表示全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值。sp_statement表示一些存儲過程或函數的執行語句。
【示例14-7】 下面是定義處理程序的幾種方式。
代碼以下:
//方法一:捕獲sqlstate_value DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='CAN NOT FIND';
//方法二:捕獲mysql_error_code DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';
//方法三:先定義條件,而後調用 DECLARE can_not_find CONDITION FOR 1146 ;
DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND';
//方法四:使用SQLWARNING DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
//方法五:使用NOT FOUND DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';
//方法六:使用SQLEXCEPTION DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
上述代碼是6種定義處理程序的方法。
第一種方法是捕獲sqlstate_value值。若是遇到sqlstate_value值爲42S02,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。
第二種方法是捕獲mysql_error_code值。若是遇到mysql_error_code值爲1146,執行CONTINUE操做,而且輸出"CAN NOT FIND"信息。
第三種方法是先定義條件,而後再調用條件。這裏先定義can_not_find條件,遇到1146錯誤就執行CONTINUE操做。
第四種方法是使用SQLWARNING。SQLWARNING捕獲全部以01開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。
第五種方法是使用NOT FOUND。NOT FOUND捕獲全部以02開頭的sqlstate_value值,而後執行EXIT操做,而且輸出"CAN NOT FIND"信息。
第六種方法是使用SQLEXCEPTION。SQLEXCEPTION捕獲全部沒有被SQLWARNING或NOT FOUND捕獲的sqlstate_value值,而後執行EXIT操做,而且輸出"ERROR"信息。
*/ -----------------------------------
DELIMITER $$
CREATE PROCEDURE testp18()
BEGIN
-- 遍歷數據結束標誌
DECLARE done INT DEFAULT FALSE;
-- 須要定義接收遊標數據的變量
declare _uname varchar(20) ;
declare _uaddress VARCHAR(20);
-- 遊標
DECLARE D_cursor CURSOR FOR select uname,uaddress from testa;
/* 遍歷數據結束標誌
--DECLARE done INT DEFAULT FALSE;
-- #放到這裏出現這個錯誤[Err] 1337 - Variable or condition declaration after cursor or handler declaration 根據錯誤的提示信息,遊標定義需在變量/條件後,HANDLER 前。 */
-- 將結束標誌綁定到遊標
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- 打開遊標
OPEN D_cursor;
--FETCH D_cursor INTO _uname, _uaddress;
--insert into testd(uname,uaddress)values(_uname,_uaddress); 這裏多加這兩句不影響後面的數據
-- 開始循環
read_loop: LOOP
-- 提取遊標裏的數據,這裏只有一個,多個的話也同樣;
FETCH next from D_cursor INTO _uname, _uaddress;-- next from能夠省略
-- 聲明結束的時候
IF done THEN
LEAVE read_loop;
END IF;
-- 這裏作你想作的循環的事件
insert into testd(uname,uaddress)values(_uname,_uaddress);
END LOOP;
-- FETCH D_cursor INTO _uname, _uaddress;這裏若是加上這兩句會增長一條數據與最後的數據相同
--insert into testd(uname,uaddress)values(_uname,_uaddress);
-- 關閉遊標
CLOSE D_cursor;
END
-- testp17()和testp18()兩個效果是同樣的 -
----------------------------------------