我想知道游标的一般替换是什么。我看到的游标的一般实现是
DECLARE @variable INT, @sqlstr NVARCHAR(MAX)
DECLARE cursor_name CURSOR
FOR select_statement --essentially to get an array for @variable
--usually it's a subset of unique ids for accounts, clients, parts, etc
OPEN cursor_name
FETCH NEXT FROM cursor_name INTO @variable
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sqlstr = N'
/* some query that uses '+ str(@variable) +' to do dirty work
such as: go through all our accounts, if it''s some subset (possible new cursor),
go through those accounts and connect this way,
map those fields and add it to our big uniform table */
'
EXEC sp_executesql @sqlstr
FETCH NEXT FROM cursor_name INTO @variable
END
CLOSE cursor_name
DEALLOCATE cursor_name
既然这么多人反对游标(对SO:Why do people hat cursors表示赞同),一般实现(最好是 SQL Server)的一般替代品是什么?
视情况而定™
围绕一个或多个游标工作的能力将取决于该游标内部要执行的内容。不知道里面发生了什么,就没有办法说出来。可能没有解决方法,您必须逐行处理。
下面是一些例子。
不成套工作
此示例是最基本的示例,您可以一次查询整个数据集或部分数据集,但创建了游标并逐行查询数据。常用的替换为
JOIN
's,CROSS APPLY
/OUTER APPLY
和其他。考虑以下数据集:
Lotr
可以通过循环遍历表来尝试查找每条记录并分别匹配。光标:
产生两个结果集
使用它时
inner join
,我们得到与一个结果集相同的结果。字符串操作
一种常见的方法是用于
FOR XML PATH('')
替换游标内的字符串操作。数据集
带字符串操作的双光标
结果
使用 FOR XML PATH('') 删除游标
*
真正的解决方法是弄清楚为什么以这种方式呈现数据,并更改应用程序/...以使其不需要这种格式,将其存储在某处,...
如果你的双手被束缚,这将是下一个最好的事情。
根据另一个表中的 Id 将前 10 个值插入到临时表中
数据
创建表 dbo.sometable(InsertTableId int, val varchar(255)); 创建表 dbo.Top10Table(Top10TableId int, InsertTableId int, val varchar(255));
光标
结果
CROSS APPLY
用和替换光标CTE
其他示例
CROSS APPLY
此处替换光标以选择每个供应商的动态项目集的示例。有时别无选择
如果您不能在集合中工作,并且必须逐行处理,您仍然可以优化游标。
加速光标的最大变化之一是添加
LOCAL FAST_FORWARD
它。看看@AaronBertrand 的这篇博文,他解释了使用或不使用
LOCAL
&之类的光标设置时性能可能存在的差异FAST_FORWARD
。没有“通用替换”——你在这里隐藏了所有“肮脏的工作”,所以很难判断在这种情况下是否有特定的替换。在某些特定情况下,您一次处理一组行,无论是使用游标、while 循环还是任何其他迭代过程,在这些情况下转换为处理所有行的基于集合的过程一次会好很多。但是还有其他事情只需要一次完成一行,例如执行存储过程或每行一些动态 SQL,跨多个数据库的相同查询等。
游标与否,无论您使用声明游标还是其他一些循环结构(请参阅这篇文章),您所暗示和链接的问题都是相同的,并且当您必须做的事情必须在一行中完成时无关紧要反正时间。因此,如果您提供有关此光标正在做什么的一些具体细节,您可能会得到一些关于如何删除光标(或者您不能)的建议,但是您可以寻找一种可以应用的神奇消除所有光标的方法所有场景都会让你非常沮丧。
恕我直言,对于进入该语言的新人的一般建议应该是始终考虑您需要对一组行做什么,而不是对一组中的每一行做什么。语言上的差异是微妙的,但至关重要。如果人们将问题视为一组数据而不是一堆单独的行,那么他们可能不太可能默认使用游标。但是,如果他们来自不同类型的编程——迭代是最好/唯一的方式——除了简单地教他们 SQL Server 没有针对这种方式进行优化之外,我不知道有什么方法可以使这一点变得明显或自动的。
您的问题仍然要求进行一般更换,我仍然认为没有这样的事情。
Doug Lane 在 YouTube 上制作了一系列名为“T-SQL Level Up”的视频。该系列的一部分探讨了删除光标的一般方法,如下所示:
SELECT
,稍后在 an 中使用的由 a 填充的变量INSERT
可能会被INSERT INTO...SELECT
语句替换)IF...ELSE
) 移动到WHERE
子句、CASE
语句、子查询等中正如此处其他出色的答案所指出的那样,对此没有灵丹妙药。但在我看来,这些视频是解决问题的一种非常直观的方法。
Doug 在每个部分都经历了三个越来越复杂的光标替换,我强烈建议您观看(因为整个交易在视频中表现得更好):