Я настраиваю задание на просмотр списка связанных серверов и выполнение определенного запроса для каждого из них. Я пытаюсь выполнить запрос внутри блока TRY-CATCH, поэтому, если есть проблема с одним конкретным сервером, я могу зарегистрировать его, но затем продолжить работу с другими серверами.
Запрос, который я выполняю внутри цикла, выглядит примерно так:
BEGIN TRY
SELECT *
FROM OPENQUERY([server1], 'SELECT 1 AS c;');
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;
PRINT 'We got past the Catch block!';
Если при подключении к серверу возникает проблема, код просто сразу завершается сбоем и не передается в CATCH
блок. Если сервер подключается, но в текущем запросе есть ошибка, например, деление на ноль, то это перехватывается, как ожидается CATCH
блоком.
Например, я создал связанный сервер с именем, которое, как я знаю, не существует. При выполнении вышеизложенного я просто получаю:
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"Login timeout expired".
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message
"An error has occurred while establishing a connection to the server.
When connecting to SQL Server 2005, this failure may be caused by the
fact that under the default settings SQL Server does not allow remote
connections.".
Msg 53, Level 16, State 1, Line 0
Named Pipes Provider: Could not open a connection to SQL Server [53].
Я читал BOL TRY-CATCH
и знаю, что он не поймает ошибки уровня 20+, которые разрывают соединение, но, похоже, это не так (это только уровень 16).
Кто-нибудь знает, почему эти ошибки не улавливаются правильно?
источник
PRINT 'Start';
в самом верху сценария, это выводится на печать в выводе, даже если затем происходит сбой соединения и сценарий завершается с ошибкой. Так что это будет указывать на ошибку во время выполнения , не так ли? Если я не понимаю это?PRINT
меня все еще былsp_testlinkedserver
вызов в сценарии. На самом деле, он не печатается с использованием моего оригинального (неудачного) скрипта. Таким образом, похоже, что это на самом деле ошибка во время компиляции, поэтому она не перехватывается.sp_testlinkedserver
вызов, но оставилSELECT
динамический SQL.PRINT
Не происходит , если вы ссылаетесь на имя сервера непосредственно, так как я предложил ранее,BEGIN TRY
никогда не вводится , так как возникает ошибка первого.После исследования кажется, что эта ошибка не обнаруживается, поскольку это ошибка времени компиляции, а не ошибка времени выполнения. Чтобы продемонстрировать это, попробуйте следующее:
Начальный
PRINT
оператор не получает вывод, и при этом ошибка деления на ноль не выполняется / перехватывается. Несуществующий сервер вызывает немедленный сбой сценария.источник
У меня недавно была похожая проблема, когда я вызывал удаленную процедуру из TRY-CATCH, и процедура не удалась из-за попытки вставить дублирующийся ключ (ошибка времени выполнения уровня 16). Блок CATCH не был вызван. Я нашел причину в этой статье: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
Решение состоит в том, чтобы установить XACT_ABORT ON в вызывающей процедуре, прежде чем вызывать удаленную процедуру. Когда XACT_ABORT включен, блок CATCH вызывается, как и ожидалось. Вы должны знать, что параметр XACT_ABORT распространяется на удаленную процедуру, и это может повлиять на ее поведение.
источник
источник