Search code examples
sqlsql-servercursortry-catch

Removal of cursor which is processing bad data


How can we remove cursor in the following scenario:

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

Here -25 value is causing the error and because of which I am forced to use the cursor. Can we do a set-based operation to achieve the same result?


Solution

  • SQL Server does not provide very good error handling within a SELECT statement. The one exception is for type conversion and the try_ functions -- but even that is relatively recently in the history of the database.

    SQL is not alone in this. The standard just does not address this point.

    The one thing you can do is use a case expression, if you understand the conditions when you will get an error:

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

    SQL Server guarantees that the when conditions are evaluated in order, stopping at the first match, and the then is evaluated after then when. I should say "under almost all circumstances"; there are some optimizations made in aggregation queries that somewhat weaken that statement.

    Many other databases have similar limitations. And in most of them, you can use a user-defined function that catches the exception. Alas, SQL Server does not allow try/catch blocks in UDFs, so this is not an option.