Захват нескольких сообщений об ошибках из одного оператора в TRY CATCH - PullRequest
10 голосов
/ 13 сентября 2010

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

Оператор является изменением типа (varchar на nvarchar), и когда он завершается неудачей, кажется, чтовернуть 2 ошибки.

Сообщение 5074, уровень 16, состояние 1, строка 1 Объект 'DF_XXX_YYY' зависит от столбца 'YYY'.

Сообщение 4922, уровень 16, состояние 9, строка 1 ALTER TABLE ALTER COLUMN Описание не выполнено, поскольку один или несколько объектов обращаются к этому столбцу.

Однако, когда я обертываю его в TRY/CATCH блок и выберите ERROR_MESSAGE(), возвращается только вторая ошибка:

ALTER TABLE ALTER COLUMN Описание не выполнено, так как один или несколько объектов имеют доступ к этому столбцу.

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

Точный оператор SQL:

begin try
    alter table XXX
    alter column YYY
    nvarchar(200)
end try
begin catch
    select ERROR_MESSAGE(), ERROR_LINE(), ERROR_NUMBER(), ERROR_PROCEDURE(), ERROR_SEVERITY(), ERROR_STATE()
end catch

Кто-нибудь знает, как я могу получить более информативное сообщение?(@@ERROR также возвращает вторую ошибку)

Ответы [ 3 ]

4 голосов
/ 25 апреля 2011

В зависимости от ваших потребностей и разрешений учетной записи, под которой вы запускаете этот скрипт, вы можете использовать DBCC OUTPUTBUFFER(@@spid).

Я натолкнулся на эту идею, читая статью Эрлен Соммарског Обработка ошибок . Он ссылается на процедуру spGET_ErrorMessage.

К сожалению, это не вполне работало в моем тестовом скрипте на SQL Server 2008, хотя, поэтому я не уверен, изменился ли формат буфера, но это может произойти с небольшим изменением! *

CREATE TABLE #foo
(
c INT DEFAULT(0)
)
ALTER TABLE #foo ALTER COLUMN c VARCHAR(10)

GO
EXEC spGET_LastErrorMessage

Фактический вывод

Msg 5074, Level 16, State 1, Line 2
The object 'DF__#foo___________c__6DCC4D03' is dependent on column 'c'.

    Msg 4922, Level 16, State 9, Line 2
    ALTER TABLE ALTER COLUMN c failed because one or more objects access this column.

Заявленный вывод

errNumber            errState    errLevel    errMessage                                                                               errInstance                                                                                                                     errProcedure    errLine
-------------------- ----------- ----------- ---------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------- --------------- -----------
5074                 1           16          The object 'DF__#foo___________c__6DCC4D03' is dependent on column 'c'.                  MARTINHP                                                                                                                        NULL            2
4922                 9           16          The object 'DF__#foo___________c__6DCC4D03' is dependent on column 'c'.ALTER TABL        MARTINHP 䄀䰀吀䔀刀 䌀伀䰀唀䴀一 挀 昀愀椀氀攀搀 戀攀挀愀甀猀攀 漀渀攀 漀爀 洀漀爀攀 漀戀樀攀挀琀猀 愀挀挀攀猀猀 琀栀椀         NULL            117
3 голосов
/ 23 марта 2015

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

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

/*Create tables */

CREATE TABLE dbo.test 
(
columna int primary key
)
GO

CREATE TABLE dbo.test2
(
columnb int 
)
GO

/*Create foreign key between these tables*/
ALTER TABLE dbo.test2  WITH CHECK ADD  CONSTRAINT [FK_test_to_test] FOREIGN KEY(columnb)
REFERENCES dbo.test  (columna)
GO
ALTER TABLE dbo.test2 CHECK CONSTRAINT [FK_test_to_test] 
GO

/* TEST 1 - only returns the last error message */
BEGIN TRY
    ALTER TABLE dbo.test 
    ALTER Column columna varchar
END TRY
BEGIN CATCH
    DECLARE  @ERROR_MESSAGE NVARCHAR(2048) = ERROR_MESSAGE()
    RAISERROR (@ERROR_MESSAGE,16,16)
END CATCH       

/* TEST 2 - Returns both messages, YAY */
BEGIN TRY
    ALTER TABLE dbo.test 
    ALTER Column columna varchar
END TRY
BEGIN CATCH
    THROW;
END CATCH       


/* Clean up */
DROP TABLE dbo.test2
DROP TABLE dbo.test 
3 голосов
/ 12 марта 2011

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

Социальный вопрос MSDN - ошибка внутреннего исключения sql

Да, это ограничение функций error_xxxxx (). Когда есть несколько сообщений об ошибках, они дают информацию только об одном из сообщений - не всегда наиболее информативном.

В следующей версии SQL Server под кодовым названием Denali есть новая команда THROW, которую вы можете использовать в обработчике перехвата и которая повторно вызывает ошибку, так что вам не придется обрабатывать ее самостоятельно. Когда вы используете THROW, обе ошибки будут повторяться

...