在存储过程中使用带有dynamicSQL的游标
我有一个在存储过程中创build的dynamicSQL语句。 我需要使用游标来遍历结果。 我很难搞清楚正确的语法。 这是我正在做的。
SELECT @SQLStatement = 'SELECT userId FROM users' DECLARE @UserId DECLARE users_cursor CURSOR FOR EXECUTE @SQLStatment --Fails here. Doesn''t like this OPEN users_cursor FETCH NEXT FROM users_cursor INTO @UserId WHILE @@FETCH_STATUS = 0 BEGIN EXEC asp_DoSomethingStoredProc @UserId END CLOSE users_cursor DEALLOCATE users_cursor
什么是正确的方法来做到这一点?
一个游标只接受一个select语句,所以如果这个SQL真的需要dynamic的话,使得你正在执行的语句的声明游标部分。 对于下面的工作你的服务器将不得不使用全局游标。
Declare @UserID varchar(100) declare @sqlstatement nvarchar(4000) --move declare cursor into sql to be executed set @sqlstatement = 'Declare users_cursor CURSOR FOR SELECT userId FROM users' exec sp_executesql @sqlstatement OPEN users_cursor FETCH NEXT FROM users_cursor INTO @UserId WHILE @@FETCH_STATUS = 0 BEGIN Print @UserID EXEC asp_DoSomethingStoredProc @UserId FETCH NEXT FROM users_cursor --have to fetch again within loop INTO @UserId END CLOSE users_cursor DEALLOCATE users_cursor
如果您需要避免使用全局游标,则还可以将dynamicSQL的结果插入到临时表中,然后使用该表来填充游标。
Declare @UserID varchar(100) create table #users (UserID varchar(100)) declare @sqlstatement nvarchar(4000) set @sqlstatement = 'Insert into #users (userID) SELECT userId FROM users' exec(@sqlstatement) declare users_cursor cursor for Select UserId from #Users OPEN users_cursor FETCH NEXT FROM users_cursor INTO @UserId WHILE @@FETCH_STATUS = 0 BEGIN EXEC asp_DoSomethingStoredProc @UserId FETCH NEXT FROM users_cursor INTO @UserId END CLOSE users_cursor DEALLOCATE users_cursor drop table #users
这个代码是一个带有游标的dynamic列的很好的例子,因为你不能在@STATEMENT中使用'+':
ALTER PROCEDURE dbo.spTEST AS SET NOCOUNT ON DECLARE @query NVARCHAR(4000) = N'' --DATA FILTER DECLARE @inputList NVARCHAR(4000) = '' DECLARE @field sysname = '' --COLUMN NAME DECLARE @my_cur CURSOR EXECUTE SP_EXECUTESQL N'SET @my_cur = CURSOR FAST_FORWARD FOR SELECT CASE @field WHEN ''fn'' then fn WHEN ''n_family_name'' then n_family_name END FROM dbo.vCard WHERE CASE @field WHEN ''fn'' then fn WHEN ''n_family_name'' then n_family_name END LIKE ''%''+@query+''%''; OPEN @my_cur;', N'@field sysname, @query NVARCHAR(4000), @my_cur CURSOR OUTPUT', @field = @field, @query = @query, @my_cur = @my_cur OUTPUT FETCH NEXT FROM @my_cur INTO @inputList WHILE @@FETCH_STATUS = 0 BEGIN PRINT @inputList FETCH NEXT FROM @my_cur INTO @inputList END RETURN
通过ODBC连接使用非关系数据库(IDMS任何人?)可以作为游标和dynamicSQL似乎是唯一path的时代之一。
select * from a where a=1 and b in (1,2)
需要45分钟的时间来响应,而没有in子句的情况下重新编写使用键集将在1秒内运行:
select * from a where (a=1 and b=1) union all select * from a where (a=1 and b=2)
如果列B的in语句包含1145行,则使用游标创buildindidivudal语句并将其作为dynamicSQL执行比使用in子句要快得多。 傻嗨?
是的,在关系数据库中没有时间应该使用游标。 我简直不敢相信我遇到过光标循环快几个数量级的例子。
首先,尽可能避免使用光标。 下面是一些看起来不可或缺的资源:
必须有15种方式失去你的光标…第1部分,介绍
逐行处理没有光标
尽pipe如此,你可能会被困在一个 – 我不太了解你的问题,以确保其中的任何一个适用。 如果是这种情况,则会遇到另一个问题 – 游标的select语句必须是实际的 SELECT语句,而不是EXECUTE语句。 你被卡住了
但是看到cmsjr(写在我写的时候)关于使用临时表的答案。 我会避免全局游标比“普通”游戏更…
在最近从Oracle切换到SQL Server(雇主偏好)之后,我注意到SQL Server中的游标支持是滞后的。 游标并不总是邪恶的,有时是必需的,有时要快得多,有时甚至比尝试通过重新安排或增加优化提示来调整复杂查询更清晰。 “游标是邪恶的”意见在SQL Server社区中更为突出。
所以我想这个答案是切换到甲骨文或给MS一个线索。
- Oracle EXECUTE IMMEDIATE到游标中
- 循环隐式游标 (
for
循环隐式定义/打开/closures游标!)
还有一个我想和你分享的例子
:D http://www.sommarskog.se/dynamic_sql.html#cursor0
这段代码对你有用。
在sql server中使用游标的例子
DECLARE sampleCursor CURSOR FOR SELECT K.Id FROM TableA K WHERE ....; OPEN sampleCursor FETCH NEXT FROM sampleCursor INTO @Id WHILE @@FETCH_STATUS <> -1 BEGIN UPDATE TableB SET ...