2009-05-20 49 views
163

我有一個以某種方式改變用戶數據的存儲過程。我把它傳遞給user_id,它做的是事情。我想在一個表上運行一個查詢,然後爲每個user_id找到運行存儲過程一次user_id如何爲查詢返回的每一行執行一次存儲過程?

我該如何爲此編寫查詢?

+5

您需要指定什麼RDBMS - 對於SQL Server,Oracle,MySql等,答案會有所不同。 – 2009-05-20 05:33:45

+5

很可能您根本不需要存儲過程。你能概述存儲過程的「什麼」嗎?也許整個過程可以表示爲單個更新語句。如果可能,通常應避免「爲每個記錄做一次」模式。 – Tomalak 2009-05-20 05:38:11

+0

您正在使用哪個數據庫? – 2009-05-20 05:38:19

回答

196

使用遊標

附錄:[MS SQL遊標示例]

declare @field1 int 
declare @field2 int 
declare cur CURSOR LOCAL for 
    select field1, field2 from sometable where someotherfield is null 

open cur 

fetch next from cur into @field1, @field2 

while @@FETCH_STATUS = 0 BEGIN 

    --execute your sproc on each row 
    exec uspYourSproc @field1, @field2 

    fetch next from cur into @field1, @field2 
END 

close cur 
deallocate cur 
在MS SQL

here's an example article

注意,遊標比基於設定的操作越慢,但比手動更快while循環;更多詳細信息in this SO question

附錄2:如果您要處理的不僅僅是幾條記錄,請先將它們拉入臨時表中,然後將光標移到臨時表上;這將防止SQL升級到表鎖並加速運行

附錄3:當然,如果您可以內聯任何存儲過程對每個用戶ID執行的操作並將整個事件作爲單個SQL更新語句,那將是最佳的

7

類似這樣的替換將需要您的表和字段名稱。

Declare @TableUsers Table (User_ID, MyRowCount Int Identity(1,1) 
Declare @i Int, @MaxI Int, @UserID nVarchar(50) 

Insert into @TableUser 
Select User_ID 
From Users 
Where (My Criteria) 
Select @MaxI = @@RowCount, @i = 1 

While @i <= @MaxI 
Begin 
Select @UserID = UserID from @TableUsers Where MyRowCount = @i 
Exec prMyStoredProc @UserID 
Select 

@i = @i + 1, @UserID = null 
End 
46

如果您需要循環嘗試更改您的方法!

在父存儲過程中,創建一個#temp表,其中包含您需要處理的數據。調用子存儲過程,#temp表將可見,並且可以對其進行處理,希望能夠處理整組數據,而不需要光標或循環。

這真的取決於這個子存儲過程在做什麼。如果你正在更新,你可以「更新」加入#temp表格,並在一個語句中完成所有工作而不需要循環。對於INSERT和DELETE也可以做同樣的事情。如果您需要使用IF執行多個更新,則可以使用#temp表將其轉換爲多個UPDATE FROM,並使用CASE語句或WHERE條件。

在數據庫中工作時,嘗試失去循環的心態,這是一個真正的性能消耗,會導致鎖定/阻塞並放慢處理速度。如果你到處循環,你的系統不能很好地擴展,當用戶開始抱怨緩慢刷新時,加速很難。

發佈您想要循環調用的此過程的內容,並且我會下注9次,您可以將它寫入一組行中。

4

這不能用用戶定義的函數來完成複製存儲過程的任何操作嗎?

SELECT udfMyFunction(user_id), someOtherField, etc FROM MyTable WHERE WhateverCondition 

其中udfMyFunction是你做一個函數具有在用戶ID和做任何你需要用它做。

多一點背景

http://www.sqlteam.com/article/user-defined-functions我同意光標真的應該儘可能地避免。它通常是可能的! (當然,我的答案假定你只是想從SP獲得輸出,而你並沒有改變實際數據,我發現「以某種方式改變了用戶數據」,這有點含糊不清原來的問題,所以我認爲我會提供這個作爲一個可能的解決方案。完全取決於你在做什麼!)

3

你可以做一個動態查詢。

declare @cadena varchar(max) = '' 
select @cadena = @cadena + 'exec spAPI ' + ltrim(id) + ';' 
from sysobjects; 
exec(@cadena); 
1

我喜歡Dave Rincon的動態查詢方式,因爲它不使用遊標,而且小巧易用。謝謝戴夫分享。

但對於我在Azure上的SQL,並在查詢一個「獨特」的需要,我不得不修改這樣的代碼:

Declare @SQL nvarchar(max); 
-- Set SQL Variable 
-- Prepare exec command for each distinctive tenantid found in Machines 
SELECT @SQL = (Select distinct 'exec dbo.sp_S2_Laser_to_cache ' + 
       convert(varchar(8),tenantid) + ';' 
       from Dim_Machine 
       where iscurrent = 1 
       FOR XML PATH('')) 

--for debugging print the sql 
print @SQL; 

--execute the generated sql script 
exec sp_executesql @SQL; 

我希望這可以幫助別人......

相關問題