как перестроить одно и то же исключение в sql server


Я хочу перестроить то же исключение в sql server, которое произошло в моем блоке try. Я могу бросить то же сообщение, но я хочу бросить ту же ошибку.

BEGIN TRANSACTION
    BEGIN TRY
            INSERT INTO Tags.tblDomain 
            (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
            COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
            declare @severity int; 
            declare @state int;

            select @severity=error_severity(), @state=error_state();

            RAISERROR(@@Error,@ErrorSeverity,@state);
            ROLLBACK TRANSACTION
    END CATCH

RAISERROR(@@Error, @ErrorSeverity, @state);

эта строка покажет ошибку, но я хочу функциональность что-то вроде этого. Это вызывает ошибку с номером ошибки 50000, но я хочу, чтобы номер erron был брошен, что я передаю @@error,

Я хочу захватить эту ошибку нет frontend

т. е.

catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}

Я хочу эту функциональность. что не может быть достигнуто с помощью raiseerror. Я не хочу давать пользовательское сообщение об ошибке на заднем конце.

RAISEERROR должен возвращать указанную ниже ошибку, когда я передаю ErrorNo, чтобы быть брошенным в catch

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

строка 14 Нарушение ограничения уникального ключа 'UK_DomainCode'. Не удается вставить дубликат ключа в объекте - Бирки.tblDomain'. Заявление было сделано завершенный.

EDIT:

в чем может быть недостаток не использования блока try catch, если я хочу, чтобы исключение обрабатывалось на интерфейсе, учитывая, что хранимая процедура содержит несколько запросов, которые необходимо выполнить

10 65

10 ответов:

вот полностью функциональный чистый пример кода для отката серии операторов, если возникает ошибка,и сообщить об ошибке.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch

SQL 2012 вводит оператор throw:

http://msdn.microsoft.com/en-us/library/ee677615.aspx

если оператор THROW указан без параметров, он должен появиться внутри блока улов. Это приводит к возникновению перехваченного исключения.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH

перестроение внутри блока CATCH (код до SQL2012, используйте оператор THROW для SQL2012 и более поздних версий):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)

Я думаю, что ваш выбор:

  • не поймать ошибку (пусть он пузырится)
  • поднимите пользовательский

в какой-то момент SQL, вероятно, введет команду reraise или возможность ловить только определенные ошибки. Но сейчас, используйте обходной путь. Извиняюсь.

вы не можете: только двигатель может выдавать ошибки менее 50000. Все, что вы можете сделать, это бросить исключение, что выглядит нравится...

смотрите мой ответ здесь, пожалуйста

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

ок, это обходной путь...: -)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

Если вы обратите внимание на блок catch, он не вызывает ошибку, но возвращает фактический номер ошибки (а также откатывает транзакцию). Теперь в вашем коде .NET, вместо того, чтобы ловить исключение, если вы используете ExecuteScalar (), вы получаете фактический номер ошибки, который вы хотите, и показываете соответствующий номер.

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

надеюсь, это поможет,

EDIT : - просто заметка, Если вы хотите получить количество записей затронутый и пытающийся использовать ExecuteNonQuery, вышеуказанное решение может не работать для вас. В противном случае, я думаю, что это будет соответствовать тому, что вам нужно. Дайте мне знать.

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

If @@ERROR > 0
Return

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

этот тип обработки ошибок parallels (pre .Net) Visual Basic 6. С нетерпением жду команда Throw в SQL Server 2012.

учитывая, что вы еще не перешли на 2012 год, один из способов реализации пузырящегося исходного кода ошибки-использовать часть текстового сообщения исключения, которое вы (повторно)выбрасываете из блока catch. Помните, что он может содержать некоторую структуру, например, текст XML для анализа кода вызывающего абонента в блоке catch.

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

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'

с точки зрения дизайна, какой смысл бросать исключения с исходными номерами ошибок и пользовательскими сообщениями? В некоторой степени это нарушает контракт интерфейса между приложениями и базой данных. Если вы хотите поймать исходные ошибки и обработать их в более высоком коде, не обрабатывайте их в базе данных. Затем, когда вы поймаете исключение, вы можете изменить сообщение, представленное пользователю, на все, что хотите. Я бы не стал этого делать, потому что это делает ваш код базы данных хм ' нет правильно. Как говорили другие, вы должны определить набор своих собственных кодов ошибок (выше 50000) и бросить их вместо этого. Затем вы можете решить проблемы целостности hanle ("повторяющиеся значения не допускаются") отдельно от потенциальных бизнес - проблем - "почтовый индекс недействителен", "не было найдено строк, соответствующих критериям" и так далее.