删除正在处理坏数据的游标

Removal of cursor which is processing bad data

在以下情况下我们如何删除游标:

DECLARE @Tablesq TABLE (numbercol INT)
INSERT INTO @Tablesq
SELECT 25 UNION all
SELECT -25 UNION all
SELECT 25 UNION all
SELECT 36

DECLARE @number INT

DECLARE sqrtcur CURSOR  FOR SELECT numbercol FROM @tablesq
OPEN sqrtcur
FETCH NEXT FROM sqrtcur INTO @number
WHILE @@FETCH_STATUS = 0
   BEGIN
         BEGIN TRY
         SELECT SQRT(@number)
         END TRY
         BEGIN CATCH
                print ERROR_MESSAGE();
         END CATCH
         FETCH NEXT FROM sqrtcur INTO @number
   END

CLOSE sqrtcur
DEALLOCATE sqrtcur

此处 -25 值导致错误,因此我被迫使用游标。我们可以做一个基于集合的操作来达到相同的结果吗?

你在找这个吗:

SELECT SQRT(numbercol)
FROM @Tablesq
WHERE numbercol > 0;

SQL 服务器在 SELECT 语句中没有提供很好的错误处理。一个例外是类型转换和 try_ 函数——但即便如此,这在数据库的历史中也是相对较新的。

SQL 并不孤单。标准只是没有解决这一点。

您可以做的一件事是使用 case 表达式,如果您了解出现错误的条件:

select (case when numbercol >= 0 then sqrt(numbercol) end)
from tablesq;

SQL 服务器保证 when 条件按顺序求值,在第一个匹配处停止,thenwhen 之后求值。我应该说 "under almost all circumstances";在聚合查询中进行了一些优化,在某种程度上削弱了该语句。

许多其他数据库也有类似的限制。在大多数情况下,您可以使用捕获异常的用户定义函数。唉,SQL 服务器不允许在 UDF 中使用 try/catch 块,所以这不是一个选项。

你可以这样做:

DECLARE @tablesq TABLE (numbercol INT)
INSERT INTO @tablesq
SELECT 25 UNION all
SELECT -25 UNION all
SELECT 25 UNION all
SELECT 36;

DECLARE @number INT;

DECLARE sqrtcur CURSOR  FOR SELECT numbercol FROM @tablesq;
DECLARE @TEST FLOAT;
OPEN sqrtcur;
FETCH NEXT FROM sqrtcur INTO @number;
WHILE @@FETCH_STATUS = 0
   BEGIN
         BEGIN TRY
            SET @TEST = SQRT(@number);
            SELECT SQRT(@number);
         END TRY
         BEGIN CATCH
                print ERROR_MESSAGE();
         END CATCH;
         FETCH NEXT FROM sqrtcur INTO @number;
   END;
CLOSE sqrtcur;
DEALLOCATE sqrtcur;