SQL Server 2000: как выйти из хранимой процедуры? - PullRequest
59 голосов
/ 08 декабря 2009

Как выйти из середины хранимой процедуры?

У меня есть хранимая процедура, в которой я хочу выручить пораньше (при попытке отладки). Я попытался позвонить RETURN и RAISERROR, и sp продолжает работать:

CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS

    print 'before raiserror'
    raiserror('this is a raised error', 18, 1)
    print 'before return'
    return -1
    print 'after return'

[snip]

Я знаю, что он продолжает работать, потому что я сталкиваюсь с ошибкой ниже. Я не вижу ни одного из моих отпечатков . Если я закомментирую большую часть хранимой процедуры:

CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS

    print 'before raiserror'
    raiserror('this is a raised error', 18, 1)
    print 'before return'
    return -1
    print 'after return'

   /*
     [snip]
   */

Тогда я не получаю свою ошибку и вижу результаты:

before raiserror
Server: Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 5
this is a raised error
before return

Итак, вопрос: как мне выйти из хранимой процедуры в SQL Server?

Ответы [ 7 ]

79 голосов
/ 08 декабря 2009

Вы можете использовать RETURN, чтобы немедленно остановить выполнение хранимой процедуры. Цитата взята из Books Online :

Безусловный выход из запроса или процедура. Возврат является немедленным и полный и может быть использован в любой точке выйти из процедуры, партии или Блок выписок. Заявления о том, что последующий ВОЗВРАТ не выполнен.

Из паранойи я попробовал ваш пример, и он выводит PRINT и немедленно останавливает выполнение.

28 голосов
/ 08 декабря 2009

Если вы не укажете серьезность 20 или выше, raiserror не остановит выполнение. См. документацию MSDN .

Обычный обходной путь должен включать return после каждого raiserror:

if @whoops = 1
    begin
    raiserror('Whoops!', 18, 1)
    return -1
    end
10 голосов
/ 08 декабря 2009

Поместите его в TRY/CATCH.

Когда RAISERROR запущен с серьезностью 11 или выше в блоке TRY, это передает управление связанному Блок CATCH

Ссылка: MSDN .

РЕДАКТИРОВАТЬ: Это работает для MSSQL 2005+, но я вижу, что вы уже пояснили, что работаете над MSSQL 2000. Я оставлю это здесь для справки.

9 голосов
/ 08 декабря 2009

Я понял, почему RETURN не безоговорочно возвращается из хранимой процедуры. Я вижу ошибку, когда хранимая процедура компилируется , а не когда она выполняется.

Рассмотрим мнимую хранимую процедуру:

CREATE PROCEDURE dbo.foo AS

INSERT INTO ExistingTable
EXECUTE LinkedServer.Database.dbo.SomeProcedure

Даже несмотря на то, что в этой процедуре stord содержится ошибка (возможно, это связано с тем, что объекты имеют разное количество столбцов, возможно, в таблице есть столбец метки времени, возможно, хранимая процедура не существует), вы все равно можете сохранить это. Вы можете сохранить его, потому что ссылаетесь на связанный сервер.

Но когда вы на самом деле выполняете хранимую процедуру, SQL Server ее компилирует и генерирует план запроса.

Моя ошибка не происходит в строке 114, она в строке 114. SQL Server не может скомпилировать хранимую процедуру, поэтому она не работает.

И именно поэтому RETURN не возвращается, потому что он даже еще не запустил .

4 голосов
/ 24 сентября 2012

Это похоже на большой код, но я нашел лучший способ сделать это.

    ALTER PROCEDURE Procedure
    AS

    BEGIN TRY
        EXEC AnotherProcedure
    END TRY
    BEGIN CATCH
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT 
            @ErrorMessage = ERROR_MESSAGE(),
            @ErrorSeverity = ERROR_SEVERITY(),
            @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                   @ErrorSeverity, -- Severity.
                   @ErrorState -- State.
                   );
        RETURN --this forces it out
    END CATCH

--Stuff here that you do not want to execute if the above failed.    

    END --end procedure
4 голосов
/ 08 декабря 2009

Это работает здесь.

ALTER PROCEDURE dbo.Archive_Session
    @SessionGUID int
AS 
    BEGIN
        SET NOCOUNT ON
        PRINT 'before raiserror'
        RAISERROR('this is a raised error', 18, 1)
        IF @@Error != 0 
            RETURN
        PRINT 'before return'
        RETURN -1
        PRINT 'after return'
    END
go

EXECUTE dbo.Archive_Session @SessionGUID = 1

Возвращает

before raiserror
Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 7
this is a raised error
1 голос
/ 08 декабря 2009

Это потому, что у вас нет операторов BEGIN и END. Вы не должны видеть отпечатки или ошибки при выполнении этого оператора, только Statement Completed (или что-то в этом роде).

...