存儲過程break
pl/sql塊是沒有存儲過程名字的,寫好後不能被其他模塊調用,而存儲過程可以用call 存儲過程名 這種格式來進行調用,而且存儲過程還能被其他的存儲過程所調用,
2. sql 存儲過程 傳入兩組數組參數
declare@nnvarchar(500)
declare@mnvarchar(500)
set@n='1,2,3,4,5'
set@m='a,b,c,d,e'
createtable#tb(nVARCHAR(500),mVARCHAR(500))
while(1=1)
begin
if(Charindex(',',@n)=0andCharindex(',',@m)=0)
begin
insertinto#tbvalues(@n,@m)
break
end
insertinto#tbvalues(Substring(@n,1,Charindex(',',@n)-1),Substring(@m,1,Charindex(',',@m)-1))
set@n=Right(@n,Len(@n)-Charindex(',',@n))
set@m=Right(@m,Len(@m)-Charindex(',',@m))
end
select*from#tb
droptable#tb
ps:要做好校驗!
3. 存儲過程的測試一直在執行,關不掉
1、存儲過程中是否有 LOOP ?
如果有 的在end loop 添加 EXIT WHEN 游標名%NOTFOUND (意思是如果沒有這個游標,就跳出)
2、沒有loop 的話
手動停止掉當前的存儲過程吧。語句如下:
--先查運行的存儲過程sid
select /*rule*/ sid from v$access where object='存儲過程名'
--通過sid 找到serial
select sid ,serial#,paddr from v$session where sid='上一句查到的sid'
--kill 掉存儲過程
alter system kill session 'sid','serial#'
4. mssql 存儲過程中循環如何寫,在循環中用什麼語句跳出循環呢,在線等
給你個例子:
for loop是這樣的:
createprocere pro
begin
declare aintdefault1;
label1: loop
if a<6then
selecta;
seta=a+1;
iterate label1;
endif;
leave label1;跳出循環
endloop label1;
end
while是這樣的:
createprocere pro
begin
declare aintdefault4;
while a<10 do
selecta;
seta=a+1;
endwhile;
end
5. mysql存儲過程報錯 找的快哭了...
加一個事務
多加幾個判斷就可以處理存儲過程中的異常了,請採納!
6. 如何給存儲過程,傳一個數組參數
方法一 分割
例:通過SQL Server存儲過程傳送數組參數刪除多條記錄
eg. ID 值為'1,2,3' 以下存儲過程就是刪除表中id號為1,2,3的記錄:
CREATE PROCEDURE DeleteNews
@ID nvarchar(500)
as
DECLARE @PointerPrev int
DECLARE @PointerCurr int
DECLARE @TId int
Set @PointerPrev=1
while (@PointerPrev < LEN(@ID))
Begin
Set @PointerCurr=CharIndex(',',@ID,@PointerPrev)
if(@PointerCurr>0)
Begin
set @TId=cast(SUBSTRING(@ID,@PointerPrev,@PointerCurr-@PointerPrev) as int)
Delete from News whereID=@TID
SET @PointerPrev = @PointerCurr+1
End
else
Break
End
--刪除最後一個,因為最後一個後面沒有逗號,所以在循環中跳出,需另外再刪除
set @TId=cast(SUBSTRING(@ID,@PointerPrev,LEN(@ID)-@PointerPrev+1) as int)
Delete from News whereID=@TID
GO
這個方法麻煩不?於是又有另外一種方法——臨時表
方法二 Table對象
傳3個參數,都是數組形式還有時間類型用存儲過程更新
@Oid = 1,2,3,4
@Did = 111,222,333,444
@DateArr = '2007-1-1,2007-1-2,2007-1-3,2007-1-4'
CREATE proc Test999
@Oid nvarchar(1000)--ID1
,@Did nvarchar(1000)--ID2
,@DateArr nvarchar(1000)--日期
AS
DECLARE @id1s varchar(8000), @id2s varchar(8000), @dates varchar(8000)
set @id1s=@Oid
set @id2s=@Did
set @dates = @DateArr
-- 調用函數實現處理
SELECT @id1s=@id1s, @id2s=@id2s,@dates = @dates
UPDATE A SET terminate_time = B.dt
FROM [Table] A,(
SELECT
id1 = CONVERT(int, Desk_id.value),
id2 = CONVERT(int, room_id.value),
dt = CONVERT(datetime, terminate_time.value)
FROM dbo.f_splitstr(@id1s) Desk_id, dbo.f_splitstr(@id2s) room_id, dbo.f_splitstr(@dates) terminate_time
WHERE Desk_id.id = room_id.id
AND Desk_id.id = terminate_time.id
) B
WHERE A.Desk_id = B.ID1 AND A.room_id = B.ID2
GO這個還用到一個函數f_splitstr
CREATE FUNCTION dbo.f_splitstr(
@str varchar(8000)
)RETURNS @r TABLE(id int IDENTITY(1, 1), value varchar(5000))
AS
BEGIN
DECLARE @pos int
SET @pos = CHARINDEX(',', @str)
WHILE @pos > 0
BEGIN
INSERT @r(value) VALUES(LEFT(@str, @pos - 1))
SELECT
@str = STUFF(@str, 1, @pos, ''),
@pos = CHARINDEX(',', @str)
IF @str > ''
INSERT @r(value) VALUES(@str)
RETURN
這個方法更加可怕~~~輾轉網路,找到了一個還不錯的方法,用OPENXML,這個SQL2000就支持了。
方法三 xml
應該用SQL2000 OpenXML更簡單,效率更高,代碼更可讀:
CREATE Procere [dbo].[ProctListUpdateSpecialList]
(
@ProctId_Array NVARCHAR(2000),
@MoleId INT
)
AS
delete from ProctListSpecial whereMoleId=@MoleId
-- If empty, return
IF (@ProctId_Array IS NULL OR LEN(LTRIM(RTRIM(@ProctId_Array))) = 0)
RETURN
DECLARE @idoc int
EXEC sp_xml_preparedocument @idoc OUTPUT, @ProctId_Array
Insert into ProctListSpecial (MoleId,ProctId)
Select
@MoleId,C.[ProctId]
FROM
OPENXML(@idoc, '/Procts/Proct', 3)
with (ProctId int ) as C
where
C.[ProctId] is not null
EXEC sp_xml_removedocument @idoc
哇,看起來還是很復雜的說。有木有更好的辦法呢?
既然是OPENXML,為啥不用XML呢?於是查到,SQL2005以上都支持XML。Good,找到一片天了。
利用SQL2005的XML/XQuery功能,可以很方便的解決傳數組參數的問題。
declare @xml xml
set @xml = '<?xml version="1.0"?>
<ArrayOfInt>
<int>1</int>
<int>2</int>
<int>3</int>
</ArrayOfInt>'
select N.value( '(text())[1]','int' ) RoomId from @xml.nodes('/ArrayOfInt/int') V(N)
結果就是
註:上面的數據類型為XML
這樣就可以給存儲過程傳一個集合了,一般是數組,比如主鍵的集合。然後可用通過主鍵集合來查詢記錄。
客戶端可用使用序列化,把list轉化成xml。不過在序列化過程中,遇到了一些小麻煩。
1. .net默認是utf-16,SQL只認識utf-8
2. 出現很討厭的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
可以用我這個類
public static class SerializeHelper
{
private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces();
static SerializeHelper()
{
//去掉 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Namespaces.Add(string.Empty, string.Empty);
}
public static string SerializeXml<T>(T obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, obj, Namespaces);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
public static T DeserializeXml<T>(string obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(obj))
{
return (T)serializer.Deserialize(reader);
}
}
}
SQL與XML,XQuery結合起來,功能會很強大的。
7. sql server 存儲過程如何對select語句的結果集進行循環操作
DECLARE
@id INT, @value VARCHAR(10);
BEGIN
-- 定義游標.
DECLARE c_test_main CURSOR FAST_FORWARD FOR
SELECT id,valueFROM test_main;
-- 打開游標.
OPEN c_test_main;
WHILE 1=1
BEGIN
-- 填充數據.
FETCH NEXT FROM c_test_main INTO @id, @value;
-- 假如未檢索到數據,退出循環.
IF@@fetch_status!= 0 BREAK;
PRINT @value;
END;
-- 關閉游標
CLOSE c_test_main;
-- 釋放游標.
DEALLOCATE c_test_main;
END;go
8. mysql存儲過程 in 怎麼用
out 表示輸出的參數,存儲過程調用 代碼 需要獲得此參數值。
in 表示輸入參數,默認為in
例1、一個簡單存儲過程游標實例
復制代碼代碼如下:
DELIMITER $$
DROP PROCEDURE IF EXISTS getUserInfo $$
CREATE PROCEDURE getUserInfo(in date_day datetime)
--
-- 實例
-- 存儲過程名為:getUserInfo
-- 參數為:date_day日期格式:2008-03-08
--
BEGIN
declare _userName varchar(12); -- 用戶名
declare _chinese int ; -- 語文
declare _math int ; -- 數學
declare done int;
-- 定義游標
DECLARE rs_cursor CURSOR FOR SELECT username,chinese,math from userInfo where datediff(createDate, date_day)=0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
-- 獲取昨天的日期
if date_day is null then
set date_day = date_add(now(),interval -1 day);
end if;
open rs_cursor;
cursor_loop:loop
FETCH rs_cursor into _userName, _chinese, _math; -- 取數據
if done=1 then
leave cursor_loop;
end if;
-- 更新表
update infoSum set total=_chinese+_math where UserName=_userName;
end loop cursor_loop;
close rs_cursor;
END$$
DELIMITER ;
例2、存儲過程游標循環跳出現
在MySQL的存儲過程中,游標操作時,需要執行一個conitnue的操作.眾所周知,MySQL中的游標循環操作常用的有三種,LOOP,REPEAT,WHILE.三種循環,方式大同小異.以前從沒用過,所以記下來,方便以後查閱.
1.REPEAT
復制代碼代碼如下:
REPEAT
Statements;
UNTIL expression
END REPEAT
demo
DECLARE num INT;
DECLARE my_string VARCHAR(255);
REPEAT
SET my_string =CONCAT(my_string,num,',');
SET num = num +1;
UNTIL num <5
END REPEAT;
2.WHILE
復制代碼代碼如下:
WHILE expression DO
Statements;
END WHILE
demo
DECLARE num INT;
DECLARE my_string VARCHAR(255);
SET num =1;
SET str ='';
WHILE num < span>10DO
SET my_string =CONCAT(my_string,num,',');
SET num = num +1;
END WHILE;
3.LOOP(這裡面有非常重要的ITERATE,LEAVE)
代碼如下 復制代碼
DECLARE num INT;
DECLARE str VARCHAR(255);
SET num =1;
SET my_string ='';
loop_label: LOOP
IF num <10THEN
LEAVE loop_label;
ENDIF;
SET num = num +1;
IF(num mod3)THEN
ITERATE loop_label;
ELSE
SET my_string =CONCAT(my_string,num,',');
ENDIF;
END LOOP;
PS:可以這樣理解ITERATE就是我們程序中常用的contiune,而ITERATE就是break.當然在MySQL存儲過程,需要循環結構有個名稱,其他都是一樣的.
例3,mysql 存儲過程中使用多游標
先創建一張表,插入一些測試數據:
復制代碼代碼如下:
DROP TABLE IF EXISTS netingcn_proc_test;
CREATE TABLE `netingcn_proc_test` (
`id` INTEGER(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20),
`password` VARCHAR(20),
PRIMARY KEY (`id`)
)ENGINE=InnoDB;
insert into netingcn_proc_test(name, password) values
('procere1', 'pass1'),
('procere2', 'pass2'),
('procere3', 'pass3'),
('procere4', 'pass4');下面就是一個簡單存儲過程的例子:
drop procere IF EXISTS test_proc;
delimiter //
create procere test_proc()
begin
-- 聲明一個標志done, 用來判斷游標是否遍歷完成
DECLARE done INT DEFAULT 0;
-- 聲明一個變數,用來存放從游標中提取的數據
-- 特別注意這里的名字不能與由游標中使用的列明相同,否則得到的數據都是NULL
DECLARE tname varchar(50) DEFAULT NULL;
DECLARE tpass varchar(50) DEFAULT NULL;
-- 聲明游標對應的 SQL 語句
DECLARE cur CURSOR FOR
select name, password from netingcn_proc_test;
-- 在游標循環到最後會將 done 設置為 1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- 執行查詢
open cur;
-- 遍歷游標每一行
REPEAT
-- 把一行的信息存放在對應的變數中
FETCH cur INTO tname, tpass;
if not done then
-- 這里就可以使用 tname, tpass 對應的信息了
select tname, tpass;
end if;
UNTIL done END REPEAT;
CLOSE cur;
end
//
delimiter ;
-- 執行存儲過程
call test_proc();
需要注意的是變數的聲明、游標的聲明和HANDLER聲明的順序不能搞錯,必須是先聲明變數,再申明游標,最後聲明HANDLER。上述存儲過程的例子中只使用了一個游標,那麼如果要使用兩個或者更多游標怎麼辦,其實很簡單,可以這么說,一個怎麼用兩個就是怎麼用的。例子如下:
復制代碼代碼如下:
drop procere IF EXISTS test_proc_1;
delimiter //
create procere test_proc_1()
begin
DECLARE done INT DEFAULT 0;
DECLARE tid int(11) DEFAULT 0;
DECLARE tname varchar(50) DEFAULT NULL;
DECLARE tpass varchar(50) DEFAULT NULL;
DECLARE cur_1 CURSOR FOR
select name, password from netingcn_proc_test;
DECLARE cur_2 CURSOR FOR
select id, name from netingcn_proc_test;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur_1;
REPEAT
FETCH cur_1 INTO tname, tpass;
if not done then
select tname, tpass;
end if;
UNTIL done END REPEAT;
CLOSE cur_1;
-- 注意這里,一定要重置done的值為 0
set done = 0;
open cur_2;
REPEAT
FETCH cur_2 INTO tid, tname;
if not done then
select tid, tname;
end if;
UNTIL done END REPEAT;
CLOSE cur_2;
end
//
delimiter ;
call test_proc_1();
上述代碼和第一個例子中基本一樣,就是多了一個游標聲明和遍歷游標。這里需要注意的是,在遍歷第二個游標前使用了set done = 0,因為當第一個游標遍歷玩後其值被handler設置為1了,如果不用set把它設置為 0 ,那麼第二個游標就不會遍歷了。當然好習慣是在每個打開游標的操作前都用該語句,確保游標能真正遍歷。當然還可以使用begin語句塊嵌套的方式來處理多個游標,例如:
復制代碼代碼如下:
drop procere IF EXISTS test_proc_2;
delimiter //
create procere test_proc_2()
begin
DECLARE done INT DEFAULT 0;
DECLARE tname varchar(50) DEFAULT NULL;
DECLARE tpass varchar(50) DEFAULT NULL;
DECLARE cur_1 CURSOR FOR
select name, password from netingcn_proc_test;
DECLARE cur_2 CURSOR FOR
select id, name from netingcn_proc_test;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur_1;
REPEAT
FETCH cur_1 INTO tname, tpass;
if not done then
select tname, tpass;
end if;
UNTIL done END REPEAT;
CLOSE cur_1;
begin
DECLARE done INT DEFAULT 0;
DECLARE tid int(11) DEFAULT 0;
DECLARE tname varchar(50) DEFAULT NULL;
DECLARE cur_2 CURSOR FOR
select id, name from netingcn_proc_test;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur_2;
REPEAT
FETCH cur_2 INTO tid, tname;
if not done then
select tid, tname;
end if;
UNTIL done END REPEAT;
CLOSE cur_2;
end;
end
//
delimiter ;
call test_proc_2();