AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 147039
Accepted
krystah
krystah
Asked: 2016-08-17 23:42:58 +0800 CST2016-08-17 23:42:58 +0800 CST 2016-08-17 23:42:58 +0800 CST

Por que essa conversão explícita está causando problemas apenas com um servidor vinculado?

  • 772

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, Modifiede Deleted, mas, neste caso, a tabela no servidor de origem não possui nenhuma informação adequada. As colunas são, portanto, explicitamente convertidas para 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 realizar esta atualização, a visualização está acionando a seguinte mensagem de erro:

Msg 7341, Nível 16, Estado 2, Linha 3 Não é possível obter o valor da linha atual da coluna "(expressão gerada pelo usuário).Expr1002" do provedor OLE DB "SQLNCLI11" para o servidor vinculado "".

Fizemos essa mudança de "conversão explícita" geralmente no servidor de origem sem preocupações e suspeito que o problema possa estar relacionado à versão dos servidores envolvidos. Não precisamos realmente aplicar esse elenco, mas parece mais limpo. No momento, estou apenas 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 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)

Versão do servidor (vinculado):

Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17 de junho de 2011 00:54:03 Copyright (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 errada não acontece com a conversão para DateTime, mas com uma coluna sendo convertida para 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.

sql-server sql-server-2008-r2
  • 5 5 respostas
  • 6993 Views

5 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2016-08-24T06:17:45+08:002016-08-24T06:17:45+08:00

    Então, consegui reproduzir o erro ao perceber que CASTestava sendo feito localmente, não na instância remota. Eu já havia recomendado mudar para o SP3 na esperança de corrigir isso (em parte devido a não ser capaz de reproduzir o erro no SP3 e em parte por ser uma boa ideia independentemente). No entanto, agora que posso reproduzir o erro, está claro que mudar para o SP3, embora provavelmente seja uma boa ideia, não vai consertar isso. E também reproduzi o erro no SQL Server 2008 R2 RTM e 2014 SP1 (usando um servidor vinculado local "loop-back" nos três casos).

    Parece que esse problema tem a ver com o local em que a consulta está sendo executada ou, pelo menos, onde parte (s) dela está sendo executada. Digo isso porque consegui fazer a CASToperação funcionar, mas apenas incluindo uma referência a um objeto de banco de dados local:

    SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
    FROM [Local].[database_name].[dbo].[table_name] rmt
    CROSS JOIN (SELECT TOP (1) 1 FROM [sys].[data_spaces]) tmp(dummy);
    

    Isso realmente funciona. Mas o seguinte obtém o erro original:

    SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
    FROM [Local].[database_name].[dbo].[table_name] rmt
    CROSS JOIN (VALUES (1)) tmp(dummy);
    

    Suponho que, quando não há referências locais, toda a consulta é enviada para o sistema remoto para ser executada e, por algum motivo, NULLs não pode ser convertida em UNIQUEIDENTIFIER, ou talvez NULLesteja sendo traduzida incorretamente pelo driver OLE DB.


    Com base nos testes que fiz, isso parece ser um bug, mas não tenho certeza se o bug está no SQL Server ou no driver SQL Server Native Client/OLEDB. No entanto, o erro de conversão ocorre dentro do driver OLEDB e, portanto, não é necessariamente um problema de conversão de INTpara UNIQUEIDENTIFIER(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 permitem a conversão INTpara DATE, mas o driver OLEDB lida com isso com sucesso, conforme mostrado em um dos testes).

    Fiz três testes. Para os dois que obtiveram sucesso, observei os planos de execução XML que mostram a consulta que está sendo executada remotamente. Para todos os três, capturei quaisquer exceções ou eventos OLEDB por meio do SQL Profiler:

    Eventos:

    • Erros e avisos
      • Atenção
      • Exceção
      • Avisos de Execução
      • Mensagem de erro do usuário
    • OLEDB
      • tudo
    • TSQL
      • todos exceto :
        • SQL:StmtRecompile
        • XQuery Tipo Estático

    Filtros de coluna:

    • Nome da Aplicação
      • NÃO COMO %Intellisense%
    • SPID
      • Maior ou igual a 50

    OS TESTES

    • Teste 1

      • CAST(NULL AS UNIQUEIDENTIFIER)isso funciona

      SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
                   , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
      FROM [Local].[TEMPTEST].[sys].[objects] rmt;
      

      Parte relevante do plano de execução XML:

                <DefinedValue>
                  <ColumnReference Column="Expr1002" />
                  <ScalarOperator ScalarString="NULL">
                    <Const ConstValue="NULL" />
                  </ScalarOperator>
                </DefinedValue>
        ...
      <RemoteQuery RemoteSource="Local" RemoteQuery=
       "SELECT 1 FROM &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;"
       />
      
    • Teste 2

      • CAST(NULL AS UNIQUEIDENTIFIER)que falha

      SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
               --  , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
      FROM [Local].[TEMPTEST].[sys].[objects] rmt;
      

      (nota: mantive a subconsulta lá, comentada, para que fosse uma diferença a menos quando comparasse os arquivos de rastreamento XML)

    • Teste 3

      • CAST(NULL AS DATE)isso funciona

      SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
               --  , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
      FROM [Local].[TEMPTEST].[sys].[objects] rmt;
      

      (nota: mantive a subconsulta lá, comentada, para que fosse uma diferença a menos quando comparasse os arquivos de rastreamento XML)

      Parte relevante do plano de execução XML:

                <DefinedValue>
                  <ColumnReference Column="Expr1002" />
                  <ScalarOperator ScalarString="[Expr1002]">
                    <Identifier>
                      <ColumnReference Column="Expr1002" />
                    </Identifier>
                  </ScalarOperator>
                </DefinedValue>
       ...
      <RemoteQuery RemoteSource="Local" RemoteQuery=
       "SELECT TOP (2) NULL &quot;Expr1002&quot; FROM &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;" 
       />
      

    Se você observar o Teste nº 3, verá que está fazendo um SELECT TOP (2) NULLno sistema "remoto". O rastreamento do SQL Profiler mostra que o tipo de dados desse campo remoto é de fato INT. 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 de INTpara DATE, algo que causará um erro no SQL Server, funciona perfeitamente no driver OLEDB. O valor remoto é NULL, por isso é retornado diretamente, portanto, o <ColumnReference Column="Expr1002" />.

    Se você observar o Teste nº 1, ele está fazendo um SELECT 1no sistema "remoto". O rastreamento do SQL Profiler mostra que o tipo de dados desse campo remoto é de fato INT. 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 de INTpara GUID(lembre-se, isso é feito dentro do driver e o OLEDB chama de "GUID"), algo que causará um erro no SQL Server, funciona muito bem no driver OLEDB. O valor remoto não NULL é , então ele é substituído por um literal NULL, 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 sucesso, mas simplesmente não pode passar de volta o conjunto de resultados. A consulta que o SQL Profiler capturou é:

    SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"
    

    Essa é exatamente a mesma consulta que está sendo feita no Teste nº 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 está sendo exibido como INT(wType = 3 = adInteger / inteiro com sinal de quatro bytes / DBTYPE_I4) enquanto o campo "client" ainda está sendo exibido como GUID(wType = 72 = adGUID / identificador exclusivo global / DBTYPE_GUID). A documentação do OLE DB não ajuda muito, pois GUID Data Type Conversions , DBDATE Data Type Conversions e I4 Data Type Conversions mostram que a conversão de I4 para GUID ou DBDATE não é suportada, mas a DATEconsulta funciona.

    Os arquivos Trace XML para os três testes estão localizados em PasteBin. Se você quiser ver os detalhes de onde cada teste difere dos outros, você pode salvá-los localmente e depois fazer um "diff" neles. Os arquivos são:

    1. NullGuidSuccess.xml
    2. NullGuidError.xml
    3. NullDateSuccess.xml

    ERGO?

    O que fazer sobre isso? Provavelmente apenas a solução alternativa que observei na seção superior, visto que o SQL Native Client -- SQLNCLI11-- está obsoleto a partir do 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:

    Aviso

    O SQL Server Native Client (SNAC) não tem suporte além do SQL Server 2012. Evite usar o SNAC em novos trabalhos de desenvolvimento e planeje modificar os aplicativos que o utilizam atualmente. O driver ODBC da Microsoft para SQL Server fornece conectividade nativa do Windows para o Microsoft SQL Server e o banco de dados SQL do Microsoft Azure.

    Para mais informações, consulte:

    • Cliente nativo do SQL Server
    • Instalando o SQL Server Native Client

    ODBC??

    Eu configurei um servidor vinculado ODBC via:

    EXEC master.dbo.sp_addlinkedserver
      @server = N'LocalODBC',
      @srvproduct=N'{my_server_name}',
      @provider=N'MSDASQL',
      @provstr=N'Driver={SQL Server};Server=(local);Trusted_Connection=Yes;';
    
    EXEC master.dbo.sp_addlinkedsrvlogin
      @rmtsrvname=N'LocalODBC',
      @useself=N'True',
      @locallogin=NULL,
      @rmtuser=NULL,
      @rmtpassword=NULL;
    

    E então tentou:

    SELECT CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
    FROM [LocalODBC].[tempdb].[sys].[objects] rmt;
    

    e recebi o seguinte erro:

    O provedor OLE DB "MSDASQL" para o servidor vinculado "LocalODBC" retornou a mensagem "A conversão solicitada não é suportada".
    Msg 7341, Nível 16, Estado 2, Linha 53
    Não é possível obter o valor da linha atual da coluna "(expressão gerada pelo usuário).Expr1002" do provedor OLE DB "MSDASQL" para o servidor vinculado "LocalODBC".


    PS

    No que se refere ao transporte de GUIDs entre servidores remotos e locais, os valores não NULL são manipulados 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):

    <RemoteQuery RemoteSource="Local" RemoteQuery=
     "SELECT {guid'00000000-0000-0000-0000-000000000000'} &quot;Expr1002&quot; FROM &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;" 
     />
    

    PPS

    Eu também testei via OPENQUERYcom a seguinte consulta:

    SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
         --, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
    FROM   OPENQUERY([Local], N'SELECT 705 AS [dummy] FROM [TEMPTEST].[sys].[objects];') rmt;
    

    e teve sucesso, 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 NULLconstante, igual ao Teste #1.

    • 13
  2. Anton Krouglov
    2016-08-23T06:05:14+08:002016-08-23T06:05:14+08:00

    Existe apenas uma solução feia - use alguma constante de data como '1900-01-01'em vez de null.

    CAST('1900-01-01' as DateTime) as Modified
    

    Após a importação, você pode atualizar as colunas de 1900-01-01volta para nulo.

    Este é um tipo de recurso/bug do SQL 2012 conforme aqui .

    Editar: substituído 1900-00-00por uma data válida 1900-01-01de acordo com o comentário @a_horse_with_no_name abaixo.

    • 4
  3. AMtwo
    2016-08-26T04:54:39+08:002016-08-26T04:54:39+08:00

    O problema está relacionado a conversões de tipo de dados (conforme abordado nos comentários).

    Considere o seguinte:

    SELECT NULL as NullColumn INTO SomeTable;
    EXEC sp_help SomeTable;
    DROP TABLE SomeTable;
    

    Observe que o NullColumné do tipo int. O SQL Server não gosta de converter intvalores em arquivos uniqueidentifier. Esta SELECTinstrução falhará em uma conversão de tipo de dados:

    --Just a SELECT from nothing
    SELECT CAST(CAST(NULL as int) as uniqueidentifier);
    --
    --or to see it from a physical table:
    SELECT NULL as NullColumn INTO SomeTable;
    SELECT CAST(NullColumn as uniqueidentifier) FROM SomeTable;
    DROP TABLE SomeTable;
    

    Msg 529, Nível 16, Estado 2, Linha 3

    A conversão explícita do tipo de dados int para identificador único não é permitida.

    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 examinar os valores específicos. Em vez disso, você precisará executar uma CASToperação de várias etapas para alterar o implícito intpara um tipo de dados que pode ser convertido de forma limpa em uniqueidentifer--o que significa converter primeiro para varchardepois para uniqueidentifier:

    --Just a SELECT from nothing
    SELECT CAST(CAST(CAST(NULL as int) as varchar) as uniqueidentifier);
    --
    --or to see it from a physical table:
    SELECT NULL as NullColumn INTO SomeTable;
    SELECT CAST(CAST(NullColumn as varchar(32)) as uniqueidentifier) FROM SomeTable;
    DROP TABLE SomeTable;
    
    • 2
  4. Scott Hodgin - Retired
    2016-08-25T06:50:19+08:002016-08-25T06:50:19+08:00

    O OP pode decidir se esta é uma resposta apropriada.

    Não tenho nenhuma prova 'absoluta', mas 'suspeito' que o problema decorre do fato de que um UniqueIdentifer é dependente do servidor e talvez o provedor esteja tendo dificuldade em descobrir de qual servidor (local ou remoto) obter esse identificador exclusivo, mesmo que seja nulo. É por isso que você provavelmente pode lançar qualquer outro tipo de dados com sucesso neste cenário, mas não o identificador único. Os tipos de dados que são 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.

    set nocount on  
    DECLARE @cmd nVARCHAR(max)
    DECLARE @datatype SYSNAME
    
    DECLARE _CURSOR CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
    FOR
    SELECT NAME
    FROM sys.types 
    
    OPEN _CURSOR
    
    FETCH NEXT
    FROM _CURSOR
    INTO @datatype
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        BEGIN TRY
            SET @cmd = 'select top 1 cast(null as ' + @Datatype + ') as CastedData from remoteserver.remotedatabase.remoteschema.remotetable'
            PRINT @cmd
            EXECUTE sp_executesql @cmd
        END TRY
    
        BEGIN CATCH
            PRINT Error_message()
        END CATCH
    
    FETCH NEXT
    FROM _CURSOR
    INTO @datatype
    END --End While
    
    CLOSE _CURSOR
    
    DEALLOCATE _CURSOR
    
    • 1
  5. xr280xr
    2019-07-26T07:58:55+08:002019-07-26T07:58:55+08:00

    Workaround: The accepted answer seems to indicate that the conversion needs to happen locally because the OLEDB driver doesn't support it.

    So I think a simple workaround (at least in the case of my query which is selecting a null uniqueidentifier in the base case of a recursive CTE) is to declare a null variable:

    declare @nullGuid as uniqueidentifier = null;
    
    --Instead of...
    CAST(NULL AS UniqueIdentifier) AS [GUID]
    
    --use
    @nullGuid AS [GUID]
    
    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve