使用SQL循环遍历非整数行

时间:2010-06-10 22:01:22

标签: sql sql-server

我知道如何使用.NET完成我的任务,但我想在SQL中完成此任务。

我需要循环遍历主键有点任意的所有行。它可以是一个或一系列字母,也可能是任何数量的不寻常的东西。

我知道我可以做这样的事......

DECLARE @numRows INT
SET @numRows = (SELECT COUNT(pkField) FROM myTable)

DECLARE @I INT SET @I = 1 WHILE (@I <= @numRows) BEGIN --Do what I need to here SET @I = @I + 1 END

...如果我的行以连续的方式编入索引,但如果不是,我对SQL的了解不够。我一直在使用“游标”,但我遇到了关于避免游标的阅读。

我发现this SO solution但我不确定这是否是我需要的?

我很感激任何想法。

2 个答案:

答案 0 :(得分:1)

如果要循环遍历行,请使用游标。按照你所展示的方式去做效率要低得多。基本上你正在做的是一个游标而不使用SQL Server的游标设施。仅仅因为你没有使用关键字CURSOR并不意味着它不是游标。从逻辑上讲,这就是你所拥有的。您的每个选择基本上都是对基础表的查询。特别是如果表没有索引,它可能比光标效率低得多。你可以采取一些措施来减少光标... FORWARD_ONLY等。有时制作静态光标会使事情变得更快,有时候会使事情变慢。阅读CURSOR声明。

现实是避免游标,你不只是使用select语句发明游标,这是愚蠢的,那些应该被解雇的人。声称这不是光标的人自欺欺人......你需要重新思考你的整个问题。有些东西在没有游标的情况下是无法完成的,对于那些游戏,有游标。基本上我会将游标定义为在表格上逐行执行操作的任何机制

无论如何,你想要做的就是你可以通过创建映射表将非数字键变成数字键:

SELECT IDENTITY(BIGINT, 1, 1) AS numKey, pkField INTO #keymap
FROM MyTable

DECLARE @I INT
SET @I = 1
WHILE (@I <= @numRows)
BEGIN
    SELECT mt.*
    FROM  myTable mt inner join #keymap km on km.pkfield = mt.pkfield
    WHERE numkey = @I
    --Do what I need to here
    SET @I = @I  + 1
END

这仍然非常糟糕,因为现在你正在对每条记录进行连接......可能会稍微好一些:

A)SELECT IDENTITY(BIGINT,1,1)AS numKey,* INTO #keymap     来自MyTable
现在#keymap是与原始表相同的表,但是使用数字键,因此您拥有的解决方案将在没有连接的情况下工作...但是如果表很大或者您想要更新它,那么这不是很好

B)而不是进行连接

SELECT IDENTITY(BIGINT, 1, 1) AS numKey, pkField INTO #keymap
FROM MyTable

DECLARE @I INT, @myKey VARCHAR(255) -- assume varchar
SET @I = 1
WHILE (@I <= @numRows)
BEGIN
    SELECT @myKey = pkfield FROM #keymap WHERE numKey = @i
    SELECT mt.*
    FROM  myTable
    WHERE pkfield = @myKey
    --Do what I need to here
    SET @I = @I  + 1
END

这样就没有连接,但你现在正在做两个查询......你甚至可能需要索引#keymap ....

最好的办法就是重新评估你的问题。有时您可以使用CASE WHEN或标识列来避免光标。这真的取决于问题。但是对于那些需要使用游标的情况,使用实际的CURSOR通常比其他方法快得多。更快的是用.NET,Java甚至Perl / Python编写程序。我有一个使用SQL Server 2000的函数,它使用了两个嵌套游标,在我放弃之前花了一个多小时。当我写一个Perl程序做同样的事情时,它只用了10分钟。与任何解释语言一样,Perl比编译语言慢得多。 Java / C / C ++ / C#可能会快10/20/30倍....所以如果你真的需要一个游标,最好用另一种编程语言来做。特别是如果您使用的是嵌入了CLR(公共语言运行时)的SQL Server 2005 ...

答案 1 :(得分:1)

如果您确实需要按顺序执行某些操作,请使用光标。许多人建议避免它们的原因是因为这种操作暗示你正在做数据库不打算做的事情。你也丢掉了许多关于数据库的好东西,比如查询优化和并行性。

这一切都归结为你在“做东西”部分需要做的事情。您可以通过简单的更新声明来实现目标。如果需要每行调用一个存储过程,则使用游标。

(如果你发布了关于你想要达到的目标的更多细节,那么我将能够进一步提供帮助)