Estou consultando dados de um servidor vinculado por meio de uma exibição no servidor de origem. A visualização deve incluir algumas colunas padronizadas, como Created
, Modified
e Deleted
, mas, neste caso, a tabela no servidor de origem não possui nenhuma informação adequada. As colunas são, portanto, explicitamente convertidas em seus respectivos tipos. Atualizei a visualização, alterando uma coluna de
NULL AS Modified
para
CAST(NULL as DateTime) as Modified
No entanto, após executar esta atualização, a exibição está acionando a seguinte mensagem de erro:
A mensagem 7341, nível 16, estado 2, linha 3 não pode obter o valor atual da linha da coluna "(expressão gerada pelo usuário) .Expr1002" do provedor OLE DB "SQLNCLI11" para o servidor vinculado "".
Fizemos essa alteração "conversão explícita" geralmente no servidor de origem sem preocupações, e suspeito que o problema esteja relacionado à versão dos servidores envolvidos. Realmente não precisamos aplicar esse elenco, mas parece mais limpo. No momento, estou curioso para saber por que isso está acontecendo.
Versão do servidor (origem):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 14 de maio de 2014 18:34:29 Direitos autorais (c) Microsoft Corporation Enterprise Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
Versão do servidor (vinculada):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17 de junho de 2011 00:54:03 Direitos autorais (c) Microsoft Corporation Enterprise Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor )
Editar
Acabei de perceber que cometi um erro ao não postar todas as colunas em questão e devo me desculpar por deixar de fora um detalhe importante. Não sei como não percebi isso antes. A questão ainda permanece, no entanto.
A conversão incorreta não acontece com a conversão para DateTime, mas com uma coluna sendo convertida em UniqueIdentifier.
Este é o culpado:
CAST(NULL AS UniqueIdentifier) AS [GUID]
UniqueIdentifiers são suportados no SQL Server 2008 R2 e, conforme mencionado nos comentários, a consulta executada pela exibição é executada corretamente no servidor vinculado.
Danish_Norwegian_CI_AS
e o servidor vinculado o agrupamentoSQL_Danish_Pref_CP1_CI_AS
, mas aCOLLATE
cláusula não pode ser aplicada àsDateTime
colunas, por isso não fui muito longe!select Null from ...
na consulta WITH ou aninhada eCAST
em outra?INT
você alterasse o tipo de dados ao fazê-lo. Não sei por que isso lhe daria essa mensagem de erro.Respostas:
Portanto, consegui reproduzir o erro depois de perceber que
CAST
estava sendo feito localmente, não na instância remota. Anteriormente, eu recomendara a migração para o SP3 na esperança de corrigir isso (parcialmente devido à impossibilidade de reproduzir o erro no SP3 e parcialmente devido a ser uma boa ideia, independentemente). No entanto, agora que posso reproduzir o erro, fica claro que a migração para o SP3, embora ainda seja provavelmente uma boa ideia, não vai corrigir isso. E também reproduzi o erro no SQL Server 2008 R2 RTM e no 2014 SP1 (usando um servidor vinculado local de "loopback" nos três casos).Parece que esse problema tem a ver com o local em que a consulta está sendo executada ou pelo menos com parte (s) dela. Digo isso porque consegui fazer a
CAST
operação funcionar, mas apenas incluindo uma referência a um objeto de banco de dados local:Isso realmente funciona. Mas o seguinte obtém o erro original:
Eu estou supondo que quando não há referências locais, toda a consulta é enviada para o sistema remoto para ser executada e, por algum motivo,
NULL
não pode ser convertido paraUNIQUEIDENTIFIER
, ou talvezNULL
esteja sendo traduzido incorretamente pelo driver OLE DB.Com base nos testes que eu fiz, isso parece ser um erro, mas não tenho certeza se o erro está no SQL Server ou no driver OLEDB / SQL Server Native Client. No entanto, o erro de conversão ocorre no driver OLEDB e, portanto, não é necessariamente um problema de conversão de
INT
paraUNIQUEIDENTIFIER
(uma conversão que não é permitida no SQL Server), pois o driver não está usando o SQL Server para fazer conversões (o SQL Server também não permitir a conversãoINT
paraDATE
, mas o driver OLEDB lida com êxito, conforme mostrado em um dos testes).Eu fiz três testes. Para os dois que foram bem-sucedidos, observei os planos de execução XML que mostram a consulta que está sendo executada remotamente. Para todos os três, capturei todos os eventos Exceptions ou OLEDB via SQL Profiler:
Eventos:
Filtros de coluna:
OS TESTES
Teste 1
CAST(NULL AS UNIQUEIDENTIFIER)
isso funcionaParte relevante do plano de execução XML:
Teste 2
CAST(NULL AS UNIQUEIDENTIFIER)
que falha(observação: mantive a subconsulta lá, comentei, para que houvesse uma diferença a menos ao comparar os arquivos de rastreamento XML)
Teste 3
CAST(NULL AS DATE)
isso funciona(observação: mantive a subconsulta lá, comentei, para que houvesse uma diferença a menos ao comparar os arquivos de rastreamento XML)
Parte relevante do plano de execução XML:
Se você observar o Teste nº 3, ele está executando um
SELECT TOP (2) NULL
no sistema "remoto". O rastreamento do SQL Profiler mostra que o tipo de dados desse campo remoto é de fatoINT
. O rastreamento também mostra que o campo no lado do cliente (ou seja, de onde estou executando a consulta) éDATE
, conforme o esperado. A conversão deINT
paraDATE
, algo que receberá um erro no SQL Server, funciona muito bem no driver OLEDB. O valor remoto éNULL
, portanto, ele é retornado diretamente, daí o<ColumnReference Column="Expr1002" />
.Se você olhar para o Teste 1, ele está executando um
SELECT 1
no sistema "remoto". O rastreamento do SQL Profiler mostra que o tipo de dados desse campo remoto é de fatoINT
. O rastreamento também mostra que o campo no lado do cliente (ou seja, de onde estou executando a consulta) éGUID
, conforme o esperado. A conversão deINT
paraGUID
(lembre-se, isso é feito no driver e o OLEDB chama de "GUID"), algo que receberá um erro no SQL Server, funciona perfeitamente no driver OLEDB. O valor remoto não éNULL
, portanto é substituído por um literalNULL
, daí o<Const ConstValue="NULL" />
.O teste nº 2 falha, portanto, não há plano de execução. No entanto, ele consulta o sistema "remoto" com êxito, mas simplesmente não pode devolver o conjunto de resultados. A consulta que o SQL Profiler capturou é:
Essa é exatamente a mesma consulta que está sendo feita no Teste 1, mas aqui está falhando. Existem outras pequenas diferenças, mas não consigo interpretar completamente a comunicação OLEDB. No entanto, o campo remoto ainda é exibido como
INT
(wType = 3 = adInteger / número inteiro assinado de quatro bytes / DBTYPE_I4) enquanto o campo "cliente" ainda é exibido comoGUID
(wType = 72 = adGUID / identificador globalmente exclusivo / DBTYPE_GUID). A documentação do OLE DB não ajuda muito, pois conversões de tipo de dados GUID , conversões de tipo de dados DBDATE e conversões de tipo de dados I4 mostram que a conversão de I4 em GUID ou DBDATE não é suportada, mas aDATE
consulta funciona.Os arquivos XML de rastreamento para os três testes estão localizados no PasteBin. Se você quiser ver os detalhes de onde cada teste difere dos outros, salve-os localmente e faça um "diff" neles. Os arquivos são:
ERGO?
O que fazer sobre isso? Provavelmente, apenas a solução alternativa que observei na seção superior, considerando que o SQL Native Client -
SQLNCLI11
- foi preterido no SQL Server 2012. A maioria das páginas do MSDN sobre o tópico do SQL Server Native Client tem o seguinte aviso no topo:Para mais informações, consulte:
ODBC ??
Eu configurei um servidor vinculado ODBC via:
E então tentei:
e recebeu o seguinte erro:
PS
No que se refere ao transporte de GUIDs entre servidores remotos e locais, valores não NULL são tratados por meio de uma sintaxe especial. Observei as seguintes informações do evento OLE DB no rastreamento do SQL Profiler quando executei
CAST(0x00 AS UNIQUEIDENTIFIER)
:PPS
Também testei via
OPENQUERY
com a seguinte consulta:e conseguiu, mesmo sem a referência de objeto local. O arquivo XML de rastreamento do SQL Profiler foi postado no PasteBin em:
NullGuidSuccessOPENQUERY.xml
O plano de execução XML mostra isso usando uma
NULL
constante, igual ao Teste # 1.fonte
Existe apenas uma solução alternativa feia - use alguma data constante como em
'1900-01-01'
vez denull
.Após a importação, você pode atualizar as colunas com
1900-01-01
volta para Nulo.Esse é o tipo de recurso / bug do SQL 2012, conforme aqui .
Editar: substituído
1900-00-00
por data válida1900-01-01
conforme o comentário @a_horse_with_no_name abaixo.fonte
uniqueidentifier
coluna. Ou talvez pudesse ser adaptado - algo comoCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]
, talvez?1900-00-00
é uma data inválida e não será aceita.O problema está relacionado às conversões de tipo de dados (conforme encontrado nos comentários).
Considere o seguinte:
Observe que o
NullColumn
é do tipoint
. O SQL Server não gosta de converterint
valores parauniqueidentifier
. EstaSELECT
declaração falhará em uma conversão de tipo de dados:Embora esse valor específico (NULL) possa ser convertido em um GUID, o SQL Server lança o erro com base na conversão do tipo de dados, antes mesmo de analisar os valores específicos. Em vez disso, você precisará executar uma
CAST
operação de várias etapas para alterar o implícitoint
para um tipo de dados que pode ser convertido corretamente em - ouniqueidentifer
que significa converter primeiro paravarchar
depoisuniqueidentifier
:fonte
O OP pode finalmente decidir se essa é uma resposta apropriada.
Não tenho provas 'absolutas', mas desconfio que o problema decorra do fato de um UniqueIdentifer ser dependente do servidor e talvez o provedor esteja tendo dificuldade em descobrir em qual servidor (local ou remoto) obterá esse identificador exclusivo, mesmo que seja nulo. É por isso que você provavelmente pode converter qualquer outro tipo de dados com êxito nesse cenário, mas não o identificador exclusivo. Os tipos de dados dependentes do 'servidor', como UNIQUEIDENTIFIERS e DATETIMEOFFSET, fornecerão o erro que você está encontrando.
Usar OPENQUERY em vez de nome de 4 partes funciona.
fonte
Uniqueidentifier
eDateTimeOffset
ser servidor dependente? Você tem alguma fonte para isso?Solução alternativa: a resposta aceita parece indicar que a conversão precisa ocorrer localmente porque o driver OLEDB não oferece suporte.
Portanto, acho que uma solução simples (pelo menos no caso da minha consulta que está selecionando um nulo
uniqueidentifier
no caso base de um CTE recursivo) é declarar uma variável nula:fonte