用遊標,和WHILE可以遍歷您的查詢中的每一條記錄並將要求的欄位傳給變數進行相應的處理
用遊標,和WHILE可以遍歷您的查詢中的每一條記錄並將要求的欄位傳給變數進行相應的處理
==================
DECLARE
@A1 VARCHAR(10),
@A2 VARCHAR(10),
@A3 INT
DECLARE CURSOR YOUCURNAME FOR SELECT A1,A2,A3 FROM YOUTABLENAME
OPEN YOUCURNAME
fetch next from youcurname into @a1,@a2,@a3
while @@fetch_status<>-1
begin
update … set …
……您要執行的操作寫在這裡
fetch next from youcurname into @a1,@a2,@a3
end
close youcurname
deallocate youcurname
—————————————
在應用程式開發的時候,我們經常可能會遇到下面的應用,我們會通過查詢資料表的記錄集,迴圈每一條記錄,通過每一條的記錄集對另一張表進行資料進行操作,如插入與更新,我們現在假設有一個這樣的業務:老師為所在班級的學生選課,選的課程如有哲學、馬克思主義政治經濟學、毛澤東思想概論、鄧小平理論這些課,現在操作主要如下:
1) 先要查詢這些還沒有畢業的這些學生的名單,畢業過後的無法進行選課;
2) 在批量的選取學生的同時,還需要新增對應的某一門課程;
3) 點新增後選課結束。
資料量少可能看不出用Java程式直接多次進行資料庫操作這種辦法實現的弱點,因為它每次在操作資料庫的時候,都存在著頻繁的和資料庫的I/O直接互動,這點效能的犧牲實屬不應該,那我們就看下面的方法,通過儲存過程的遊標方法來實現:建立儲存過程:
Create PROCEDURE P_InsertSubject
@SubjectId int
AS
DECLARE rs CURSOR LOCAL SCROLL FOR
select studentid from student where StudentGradu = 1
OPEN rs
FETCH NEXT FROM rs INTO @tempStudentID
WHILE @@FETCH_STATUS = 0
BEGIN
Insert SelSubject values (@SubjectId,@tempStudentID)
FETCH NEXT FROM rs INTO @tempStudentID
END
CLOSE rs
GO
使用遊標對記錄集迴圈進行處理的時候一般操作如以下幾個步驟:
1、把記錄集傳給遊標;
2、開啟遊標
3、開始迴圈
4、從遊標中取值
5、檢查那一行被返回
6、處理
7、關閉迴圈
8、關閉遊標
上面這種方法在效能上面無疑已經是提高很多了,但我們也想到,在儲存過程編寫的時候,有時候我們儘量少的避免使用遊標來進行操作,所以我們還可以對上面的儲存過程進行改造,使用下面的方法來實現:
Create PROCEDURE P_InsertSubject
@SubjectId int
AS
declare @i int,
@studentid
DECLARE @tCanStudent TABLE
(
studentid int
,FlagID TINYINT
)
BEGIN
insert @tCanStudent select studentid,0 from student where StudentGradu = 1
SET @i=1
WHILE( @i>=1)
BEGIN
SELECT @studentid=’’
SELECT TOP 1 @studentid = studentid FROM @tCanStudent WHERE flagID=0
SET @[email protected]@ROWCOUNT
IF @i<=0 GOTO Return_Lab
Insert SelSubject values (@SubjectId,@studentid)
IF @@error=0
UPDATE @tCanStudent SET flagID=1 WHERE studentid = @studentid
Return_Lab:
END
End
GO
我們現在再來分析以上這個儲存過程,它實現的方法是先把滿足條件的記錄集資料存放到一個表變數中,並且在這個表變數中增加一個FLAGID進行資料初始值為0的存放,然後去迴圈這個記錄集,每迴圈一次,就把對應的FLAGID的值改成1,然後再根據迴圈來查詢滿足條件等於0的情況,可以看到,每迴圈一次,處理的記錄集就會少一次,然後迴圈的往選好課程表裡面插入,直到記錄集的條數為0時停止迴圈,此時完成操作。
比較以上的幾種迴圈方法的應用,就會知道,有時候可能對於同一種功能我們實現的方法不同,而最終應用程式效能的影響的差異就會很大,第二種、第三種就大大的減少的資料庫互動I/O操作的頻繁,會節省很多時間,方法三又避免用遊標又可以節省不必要的開銷。
使用SQL的Agent可以執行計劃任務,把寫好的SQL語句放在計劃任務裡,可以達到奇妙的效果,如定時備份資料,定時執行特定操作等等,當涉及迴圈操作很多條資料時,這裡就要使用遊標了,當然SQL中也有迴圈語句,如使用While。不過while的功能只能實現一般的操作,遊標的功能更為強大些,可在一個指定的一個集合內迴圈操作資料,實現動態操作,那就更牛了,呵呵,以下資料供存檔用。
WHILE
設定重複執行 SQL 語句或語句塊的條件。只要指定的條件為真,就重複執行語句。可以使用 BREAK 和 CONTINUE 關鍵字在迴圈內部控制 WHILE 迴圈中語句的執行。
語法
WHILE Boolean_expression
{ sql_statement | statement_block }
[ BREAK ]
{ sql_statement | statement_block }
[ CONTINUE ]
引數
Boolean_expression
返回 TRUE 或 FALSE 的表示式。如果布林表示式中含有 SELECT 語句,必須用圓括號將 SELECT 語句括起來。
{sql_statement | statement_block}
Transact-SQL 語句或用語句塊定義的語句分組。若要定義語句塊,請使用控制流關鍵字 BEGIN 和 END。
BREAK
導致從最內層的 WHILE 迴圈中退出。將執行出現在 END 關鍵字後面的任何語句,END 關鍵字為迴圈結束標記。
CONTINUE
使 WHILE 迴圈重新開始執行,忽略 CONTINUE 關鍵字後的任何語句。
註釋
如果嵌套了兩個或多個 WHILE 迴圈,內層的 BREAK 將導致退出到下一個外層迴圈。首先執行內層迴圈結束之後的所有語句,然後下一個外層迴圈重新開始執行。
示例
declare @i int
set @i=1
while @i<30
begin
insert into test (userid) values(@i)
set @[email protected]+1
end
------------------------------------------------------------
while 條件
begin
執行操作
set @[email protected]+1
end
A. 在巢狀的 IF…ELSE 和 WHILE 中使用 BREAK 和 CONTINUE
在下例中,如果平均價格少於 $30,WHILE 迴圈就將價格加倍,然後選擇最高價。如果最高價少於或等於 $50,WHILE 迴圈重新啟動並再次將價格加倍。該迴圈不斷地將價格加倍直到最高價格超過 $50,然後退出 WHILE 迴圈並列印一條訊息。
USE pubs
GO
WHILE (SELECT AVG(price) FROM titles) < $30
BEGIN
UPDATE titles
SET price = price * 2
SELECT MAX(price) FROM titles
IF (SELECT MAX(price) FROM titles) > $50
BREAK
ELSE
CONTINUE
END
PRINT ‘Too much for the market to bear’
B. 在帶有遊標的過程中使用 WHILE
以下的 WHILE 結構是名為 count_all_rows 過程中的一部分。下例中,該 WHILE 結構測試用於遊標的函式 @@FETCH_STATUS 的返回值。因為 @@FETCH_STATUS 可能返回 –2、-1 或 0,所以,所有的情況都應進行測試。如果某一行在開始執行此儲存過程以後從遊標結果中刪除,將跳過該行。成功提取 (0) 後將執行 BEGIN…END 迴圈內部的 SELECT 語句。
單變數迴圈
USE pubs
DECLARE tnames_cursor CURSOR
FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
OPEN tnames_cursor
DECLARE @tablename sysname
–SET @tablename = ‘authors’
FETCH NEXT FROM tnames_cursor INTO @tablename
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
SELECT @tablename = RTRIM(@tablename)
EXEC (‘SELECT ‘’’ + @tablename + ‘’’ = count(*) FROM ’
+ @tablename )
PRINT ’ ’
END
FETCH NEXT FROM tnames_cursor INTO @tablename
END
CLOSE tnames_cursor
DEALLOCATE tnames_cursor
多變數迴圈
CREATE PROCEDURE my_FeeCount AS
declare @到期時間 char(10)
declare @片區 char(20)
declare @繳費使用者數 char(10)
declare @sql char(2000)
declare cur_data cursor for
select convert(varchar(10),到期時間,120) as 到期時間 ,片區,count(distinct main_id) as 繳費使用者數
from V_aipu_fee where 提交時間>=convert(varchar(10),getdate()-90,120) and 提交時間
and 收費型別=‘續費收費’
Group by convert(varchar(10),到期時間,120),片區
order by convert(varchar(10),到期時間,120)
open cur_data
fetch next from cur_data into @到期時間,@片區,@繳費使用者數
while(@@fetch_status = 0)
begin
set @sql=‘update ‘+RTRIM(@片區)+‘實收=’+RTRIM(@片區)+‘實收+’+RTRIM(@繳費使用者數)+’ where 收費日期=’’’+RTRIM(@到期時間)+’’’’
print @sql
fetch next from cur_data into @到期時間,@片區,@繳費使用者數
end
close cur_data
瀋陽專業治療皰疹醫院:http://www.sdjk99.com/
瀋陽治療性病醫院哪家好:http://www.sy360jk.com/