Estoy configurando un trabajo para recorrer una lista de servidores vinculados y ejecutar una consulta específica para cada uno. Estoy tratando de ejecutar la consulta dentro de un bloque TRY-CATCH, así que si hay un problema con un servidor en particular, puedo iniciar sesión pero luego continuar con los otros servidores.
La consulta que estoy ejecutando dentro del bucle se ve así:
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!';
Si hay un problema al conectarse al servidor, el código simplemente falla inmediatamente y no se transfiere al CATCHbloque. Si el servidor se conecta pero hay un error en la consulta real, por ejemplo, dividir por cero, entonces el CATCHbloque lo detecta como se esperaba .
Por ejemplo, creé un servidor vinculado a un nombre que sé que no existe. Al ejecutar lo anterior solo obtengo:
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].
He leído BOL TRY-CATCHy sé que no detectará errores de nivel 20+ que rompan la conexión, pero este no parece ser el caso (este es solo el nivel 16).
¿Alguien sabe por qué estos errores no se detectan correctamente?
fuente

PRINT 'Start';en la parte superior de la secuencia de comandos, esto se imprime en la salida, a pesar de que la conexión falla y la secuencia de comandos se cierra con el error. Entonces, esto indicaría un error de tiempo de ejecución, ¿no? ¿A menos que lo esté malentendiendo?PRINTtodavía tenía lasp_testlinkedserverllamada en el guión. De hecho, no se imprime usando mi secuencia de comandos original (fallida). Entonces parece que esto es en realidad un error en tiempo de compilación , por lo que no queda atrapado.sp_testlinkedserverllamada, pero dejé elSELECTSQL dinámico. ElPRINTno ocurre si hace referencia el nombre del servidor directamente, por lo que me había sugerido anteriormente,BEGIN TRYno se introduce porque el error se planteó por primera vez.Después de la investigación, parece que este error no se detecta, ya que es un error en tiempo de compilación en lugar de un error en tiempo de ejecución. Para demostrar esto, intente lo siguiente:
La
PRINTdeclaración inicial no obtiene salida, ni el error de división por cero se ejecuta / captura. El servidor inexistente hace que el script falle inmediatamente.fuente
Recientemente tuve un problema similar en el que llamé a un procedimiento remoto desde un TRY-CATCH y el procedimiento falló debido al intento de insertar una clave duplicada (error de tiempo de ejecución de nivel 16). El bloque CATCH no fue invocado. Encontré la razón en este artículo: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx
La solución es SET XACT_ABORT ON en el procedimiento de llamada antes de invocar el procedimiento remoto. Cuando XACT_ABORT está en el bloque CATCH, se invoca como se esperaba. Debe tener en cuenta que la configuración XACT_ABORT se propaga al procedimiento remoto y eso puede afectar su comportamiento.
fuente
fuente