Estoy consultando datos de un servidor vinculado a través de una vista en el servidor de origen. La vista debe incluir un par de columnas estandarizadas, como Created
, Modified
y Deleted
, pero en este caso la tabla en el servidor de origen no tiene ninguna información adecuada. Por lo tanto, las columnas se convierten explícitamente a sus respectivos tipos. Actualicé la vista, cambiando una columna de
NULL AS Modified
a
CAST(NULL as DateTime) as Modified
Sin embargo, después de realizar esta actualización, la vista está activando el siguiente mensaje de error:
Mensaje 7341, Nivel 16, Estado 2, Línea 3 No se puede obtener el valor de fila actual de la columna "(expresión generada por el usuario) .Expr1002" del proveedor OLE DB "SQLNCLI11" para el servidor vinculado "".
Hemos realizado este cambio de "conversión explícita" generalmente en el servidor de origen sin preocupaciones, y sospecho que el problema podría estar relacionado con la versión de los servidores involucrados. Realmente no necesitamos aplicar este yeso, pero se siente más limpio. En este momento tengo curiosidad de saber por qué sucede esto.
Versión del servidor (origen):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 14 de mayo de 2014 18:34:29 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) en Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
Versión del servidor (vinculado):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17 de junio de 2011 00:54:03 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) en Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor )
Editar
Me acabo de dar cuenta de que cometí un error al no publicar todas las columnas en cuestión, y debo disculparme por dejar de lado un detalle importante. No sé cómo no me di cuenta de esto antes. Sin embargo, la pregunta aún permanece.
La conversión errónea no ocurre con la conversión a DateTime, sino con una columna que se convierte a UniqueIdentifier.
Este es el culpable:
CAST(NULL AS UniqueIdentifier) AS [GUID]
UniqueIdentifiers son compatibles con SQL Server 2008 R2 y, como se menciona en los comentarios, la consulta realizada por la vista se ejecuta bien en el servidor vinculado.
Danish_Norwegian_CI_AS
y el servidor vinculado tiene la intercalaciónSQL_Danish_Pref_CP1_CI_AS
, pero laCOLLATE
cláusula no se puede aplicar a lasDateTime
columnas, por lo que no he avanzado mucho.select Null from ...
CON o consulta anidada yCAST
en otra?INT
si hubiera cambiado el tipo de datos al hacerlo. Sin embargo, no sé por qué eso le daría ese mensaje de error.Respuestas:
Entonces, pude reproducir el error después de darme cuenta de que
CAST
se estaba haciendo localmente, no en la instancia remota. Anteriormente había recomendado pasar al SP3 con la esperanza de solucionarlo (en parte debido a que no podía reproducir el error en SP3 y en parte debido a que era una buena idea, independientemente). Sin embargo, ahora que puedo reproducir el error, está claro que pasar al SP3, aunque probablemente sea una buena idea, no va a solucionarlo. Y también reproduje el error en SQL Server 2008 R2 RTM y 2014 SP1 (utilizando un servidor vinculado local "en bucle" en los tres casos).Parece que este problema tiene que ver con dónde se está ejecutando la consulta, o al menos dónde se están ejecutando parte (s) de la misma. Digo esto porque pude hacer que la
CAST
operación funcione, pero solo al incluir una referencia a un objeto DB local:Eso realmente funciona. Pero lo siguiente obtiene el error original:
Supongo que cuando no hay referencias locales, toda la consulta se envía al sistema remoto para que se ejecute, y por alguna razón
NULL
no se puede convertirUNIQUEIDENTIFIER
, o tal vez elNULL
controlador OLE DB lo está traduciendo incorrectamente.Según las pruebas que he realizado, esto parecería ser un error, pero no estoy seguro de si el error se encuentra en SQL Server o en el controlador SQL Server Native Client / OLEDB. Sin embargo, el error de conversión ocurre dentro del controlador OLEDB, por lo que no es necesariamente un problema de conversión de
INT
aUNIQUEIDENTIFIER
(una conversión que no está permitida en SQL Server) ya que el controlador no está usando SQL Server para realizar conversiones (SQL Server tampoco permite la conversiónINT
aDATE
, sin embargo, el controlador OLEDB lo maneja con éxito, como se muestra en una de las pruebas).Hice tres pruebas. Para los dos que tuvieron éxito, miré los planes de ejecución XML que muestran la consulta que se ejecuta de forma remota. Para los tres, capturé cualquier excepción o evento OLEDB a través de SQL Profiler:
Eventos:
Filtros de columna:
LOS EXÁMENES
Prueba 1
CAST(NULL AS UNIQUEIDENTIFIER)
eso funcionaPorción relevante del plan de ejecución XML:
Prueba 2
CAST(NULL AS UNIQUEIDENTIFIER)
eso falla(nota: mantuve la subconsulta allí, comenté, de modo que sería una diferencia menos cuando comparé los archivos de rastreo XML)
Prueba 3
CAST(NULL AS DATE)
eso funciona(nota: mantuve la subconsulta allí, comenté, de modo que sería una diferencia menos cuando comparé los archivos de rastreo XML)
Porción relevante del plan de ejecución XML:
Si nos fijamos en la Prueba # 3, está haciendo un
SELECT TOP (2) NULL
en el sistema "remoto". La traza del Analizador de SQL muestra que el tipo de datos de este campo remoto es de hechoINT
. El seguimiento también muestra que el campo en el lado del cliente (es decir, desde donde estoy ejecutando la consulta) esDATE
, como se esperaba. La conversión deINT
aDATE
, algo que obtendrá un error en SQL Server, funciona bien dentro del controlador OLEDB. El valor remoto esNULL
, por lo que se devuelve directamente, de ahí el<ColumnReference Column="Expr1002" />
.Si nos fijamos en la Prueba # 1, está haciendo un
SELECT 1
en el sistema "remoto". La traza del Analizador de SQL muestra que el tipo de datos de este campo remoto es de hechoINT
. El seguimiento también muestra que el campo en el lado del cliente (es decir, desde donde estoy ejecutando la consulta) esGUID
, como se esperaba. La conversión deINT
aGUID
(recuerde, esto se realiza dentro del controlador, y OLEDB lo llama "GUID"), algo que obtendrá un error en SQL Server, funciona bien dentro del controlador OLEDB. El valor remoto no esNULL
, por lo que se reemplaza con un literalNULL
, de ahí el<Const ConstValue="NULL" />
.La prueba # 2 falla, por lo que no hay un plan de ejecución. Sin embargo, consulta el sistema "remoto" con éxito, pero simplemente no puede devolver el conjunto de resultados. La consulta que capturó SQL Profiler es:
Esa es exactamente la misma consulta que se está haciendo en la Prueba # 1, pero aquí está fallando. Hay otras diferencias menores, pero no puedo interpretar completamente la comunicación OLEDB. Sin embargo, el campo remoto todavía se muestra como
INT
(wType = 3 = adInteger / entero de cuatro bytes con signo / DBTYPE_I4) mientras que el campo "cliente" todavía se muestra comoGUID
(wType = 72 = adGUID / identificador único global / DBTYPE_GUID). La documentación de OLE DB no ayuda mucho, ya que las conversiones de tipo de datos GUID , las conversiones de tipo de datos DBDATE y las conversiones de tipo de datos I4 muestran que la conversión de I4 a GUID o DBDATE no es compatible, pero laDATE
consulta funciona.Los archivos XML Trace para las tres pruebas se encuentran en PasteBin. Si desea ver los detalles de dónde difiere cada prueba de las demás, puede guardarlas localmente y luego hacer una "diferencia" en ellas. Los archivos son:
¿ES DECIR?
¿Qué hacer al respecto? Probablemente solo la solución que anoté en la sección superior, dado que el SQL Native Client -
SQLNCLI11
está en desuso a partir de SQL Server 2012. La mayoría de las páginas de MSDN sobre el tema del SQL Server Native Client tienen el siguiente aviso en el parte superior:Para más información, consulte:
ODBC ??
Configuré un servidor vinculado ODBC a través de:
Y luego probé:
y recibió el siguiente error:
PD
En lo que se refiere al transporte de GUID entre servidores remotos y locales, los valores no NULL se manejan mediante una sintaxis especial. Noté la siguiente información del evento OLE DB en el seguimiento del Analizador de SQL cuando ejecuté
CAST(0x00 AS UNIQUEIDENTIFIER)
:PPS
También probé a través
OPENQUERY
de la siguiente consulta:y tuvo éxito, incluso sin la referencia de objeto local. El archivo XML de seguimiento de SQL Profiler se ha publicado en PasteBin en:
NullGuidSuccessOPENQUERY.xml
El plan de ejecución XML lo muestra usando una
NULL
constante, igual que en la Prueba # 1.fuente
Solo hay una solución fea: use una constante de fecha como en
'1900-01-01'
lugar denull
.Después de la importación, puede actualizar las columnas con
1900-01-01
Back to Null.Esta es una especie de característica / error de SQL 2012 según aquí .
Editar: reemplazado
1900-00-00
con una fecha válida1900-01-01
según el comentario @a_horse_with_no_name a continuación.fuente
uniqueidentifier
columna. O tal vez podría adaptarse, ¿algo asíCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]
, tal vez?1900-00-00
es una fecha inválida y no será aceptada.El problema está relacionado con las conversiones de tipos de datos (como se indica en los comentarios).
Considera lo siguiente:
Tenga en cuenta que el
NullColumn
es de tipoint
. A SQL Server no le gusta convertirint
valores auniqueidentifier
. EstaSELECT
declaración fallará en una conversión de tipo de datos:Si bien este valor específico (NULL) se puede convertir a un GUID, SQL Server arroja el error en función de la conversión del tipo de datos, incluso antes de mirar los valores específicos. En su lugar, deberá realizar una
CAST
operación de varios pasos para cambiar lo implícitoint
a un tipo de datos que se pueda convertir limpiamente en, lo queuniqueidentifer
significa enviar primerovarchar
auniqueidentifier
:fuente
El OP finalmente puede decidir si esta es una respuesta apropiada.
No tengo pruebas "absolutas", pero "sospecho" que el problema se debe al hecho de que un UniqueIdentifer depende del servidor y tal vez el proveedor tiene dificultades para determinar de qué servidor (local o remoto) obtener este identificador único, aunque sea nulo. Es por eso que probablemente pueda emitir cualquier otro tipo de datos con éxito en este escenario, pero no un identificador único. Los tipos de datos que dependen del 'servidor' como UNIQUEIDENTIFIERS y DATETIMEOFFSET le darán el error que está encontrando.
Usar OPENQUERY en lugar del nombre de 4 partes funciona.
fuente
Uniqueidentifier
yDateTimeOffset
siendo dependiente del servidor? ¿Tienes alguna fuente para esto?Solución alternativa: la respuesta aceptada parece indicar que la conversión debe realizarse localmente porque el controlador OLEDB no la admite.
Entonces, creo que una solución simple (al menos en el caso de mi consulta que selecciona un nulo
uniqueidentifier
en el caso base de un CTE recursivo) es declarar una variable nula:fuente