2016-06-30 3 views
0

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

DECLARE @ErrorMessage varchar(1000) 
BEGIN TRY 
    EXEC('SELECT AA,BB FROM TABLE')--neither column AA nor BB exists 
END TRY 
BEGIN CATCH 
SET @ErrorMessage = 'ERRORMESSAGE: ' + Error_Message() 
PRINT @ErrorMessage 
END CATCH 

Запроса будет только высказать свое мнение, что колонка BB не найдена, но не может показать, что столбец АА также не существует.

Или другой пример, поставив этот запрос в TRY блоке

EXEC('CREATE SCHEMA abc AUTHORIZATION [dbo]') --schema abc already exists 

Это acutally поднять ошибку «схема уже существует» первая, то другая ошибка «не может создать схему, см предыдущей ошибки», но теперь 1-я ключевая ошибка, содержащая ключевую информацию, была «съедена».

Как показать все сообщения об ошибках?

+3

На самом деле, я думаю, что это ловит * первый * ошибка не последний. Если вы не восстановите ошибку, двигатель не сможет продолжить обработку. –

+0

@ GordonLinoff верен. Как только первая ошибка будет брошена, двигатель не будет обрабатываться дальше. Поэтому вам не нужно беспокоиться о том, чтобы поймать несколько ошибок. – Sam

+0

@ GordonLinoff. Да, если есть несколько запросов, он остановится при первом запросе; но моя вещь - это один запрос, генерирующий несколько ошибок (как и мой пример, создание схемы или использование SP или EXEC (@query), что содержащий запрос выбирает сразу два недопустимых столбца). – a4194304

ответ

1
  • вы можете использовать RAISERROR ВНУТРИ TRY-CATCH БЛОКОВ

Иван находится прямо около ERROR_MESSAGE и как TRY-CATCH может удалить надежный характер вашего запроса, однако, это происходит только когда SEVERITY сообщения выше 10 в блоке TRY. Таким образом, фокус в том, чтобы установить тяжесть под 11.

Ошибка возвращается вызывающему если RAISERROR запускается:

  • Вне пределов любого TRY блока.
  • С серьезностью 10 или ниже в блоке TRY.
  • С серьезностью 20 или выше, которая завершает работу базы данных .

MSDN - RAISERROR

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

Поскольку фатальные ошибки будут вашими ошибками, я предлагаю вам выполнить тестовые запросы и DDL команд перед их запуском.Например, вместо того, чтобы слепо пытаться EXEC('CREATE SCHEMA abc AUTHORIZATION [dbo]'), вы можете попробовать это одноранговое сообщение вместо:

DECLARE @SCHEMA NVARCHAR(10) 
DECLARE @Message NVARCHAR(255) 
SET @SCHEMA = N'abc' 
SET @Message = N'The Schema ' + @SCHEMA + ' already exists.' 

IF SCHEMA_ID(@SCHEMA) IS NOT NULL 
EXEC('CREATE SCHEMA abc AUTHORIZATION [dbo]') 
ELSE RAISERROR(@Message, 10, 1) 
--result: The Schema abc already exists. 

Есть много способов проверки достоверности динамической SQL, DDL и DML, в том числе полезных функций, таких как OBJECT_ID, OBJECT_NAME , DATABASE_ID и т. Д., Где вы проверите безопасно, а затем запустите соответствующее сообщение RAISERROR для каждой ошибки.

+0

Хорошо, если у вас еще нет схемы abc, она проходит. Но ты получил идею. :) –

0

Убрать TRY-CATCH, если возможно - разделить операторы скриптов на несколько отдельных партий с GO.

TRY-CATCH реагирует на первое исключение и нарушает выполнение TRY-блока:

Если ошибка происходит в блоке TRY, управление передается в другую группу операторов, которая заключена в CATCH блоке.

https://msdn.microsoft.com/en-us/library/ms175976.aspx

Так поведение TRY-CATCH скорее напротив вашего намерения.

GO устанавливает окончание партии. Многие из ошибок даже не разбивают пакет, потому что у них есть low severity, поэтому для некоторых случаев нет необходимости даже разбить скрипт на многие партии.

В качестве примера здесь приведен пример фиктивной сценария для тестирования или какого-бытового назначения (не для производства, конечно), что порождает множество ошибок:

create proc SomeProc as 
begin 
    exec('select uknown from non_existent') 
end 
GO 
drop table #test1 
drop table #test2 
GO 
drop table #test3 
GO 
create table #test1 (id int primary key) 

insert into #test1(id) 
exec SomeProc 

insert into #test 
values (1) 

insert into #test1 
values (1) 
GO 
insert into #test1 
values (11) 

insert into #test1 
values (11) 

insert into #test 
values (22) 
GO 
select * from #test1 
GO 
drop table #test 
GO 
drop table #test 
drop proc SomeProc 
select object_id('SomeProc', 'P') 
GO 

он дает выход выбирает:

enter image description here

и все сообщения:

Msg 3701, Level 11, St ate 5, Line 7 Невозможно удалить таблицу «# test2», , потому что она не существует или у вас нет разрешения.

Msg 3701, Level 11, State 5, Line 9 Невозможно отказаться от таблицы '# test3', потому что у нее не существует или у вас нет разрешения.

Msg 208, Level 16, State 1, Строка 11 Недопустимое имя объекта 'non_existent'.

(0 строк (ы) пострадавших)

Msg 208, уровень 16, состояние 0, строка 16 Недопустимый объект имя '#test'.

(1 ряд (ы) пострадавшие)

Сообщи 2627, Уровень 14, состояние 1, строка 25 Нарушение первичного ключ 'ПК __ # test1____3213E83FF35979C1'. Невозможно вставить дублирующий ключ в объекте 'dbo. # Test1'. Значение дублирующегося ключа равно (11). Заявление было прекращено.

Msg 208, Level 16, State 0, Line 28 Неверное имя объекта '#test'.

(1 строка (s) пострадавших)

Msg 3701, Level 11, Состояние 5, строка 33 Невозможно удалить таблицу '#test', потому что он не существует, или у вас нет разрешения.

Msg 3701, уровень 11, состояние 5, строка 35 Невозможно отказаться от таблицы '#test', потому что она не существует или у вас нет разрешения.

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

+0

Он может и, вероятно, должен использовать TRY-Block для серьезных фатальных ошибок. Уровни ошибок могут быть установлены до 11, которые не будут передавать вызов блоку catch. [MSDN-RAISERROR] (https://msdn.microsoft.com/en-us/library/ms178592.aspx) –

+0

@IvanStarostin благодарит за такое размышление. Но по моему упоминанию _print_ я на самом деле подразумеваю код 'PRINT @ errormsg', так что он эквивалентен его захвату и журналу. любые другие решения – a4194304

+0

@clifton_h Я думаю, что это хорошая идея, но как установить уровень ошибки менее 11, даже на самом деле это общий уровень 15 или 16? – a4194304

Смежные вопросы