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 / 42837
Accepted
Andrey
Andrey
Asked: 2013-05-23 12:19:20 +0800 CST2013-05-23 12:19:20 +0800 CST 2013-05-23 12:19:20 +0800 CST

Por que os servidores vinculados têm uma limitação de 10 ramificações em uma expressão CASE?

  • 772

Por que essa CASEexpressão:

SELECT CASE column 
        WHEN 'a' THEN '1' 
        WHEN 'b' THEN '2' 
        ... c -> i
        WHEN 'j' THEN '10' 
        WHEN 'k' THEN '11'  
    END [col] 
FROM LinkedServer.database.dbo.table

Produzir este resultado?

Mensagem de erro: Msg 8180, Nível 16, Estado 1, Linha 1
Instrução(ões) não pôde(m) ser preparada(s).
Msg 125, Nível 15, Estado 4, Linha 1 As
expressões de caso só podem ser aninhadas no nível 10.

Claramente não há uma CASEexpressão aninhada aqui, embora haja mais de 10 "ramificações".

Outra esquisitice. Esta função com valor de tabela embutida produz o mesmo erro:

ALTER FUNCTION [dbo].[fn_MyFunction]
(   
     @var varchar(20)
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT CASE column 
            WHEN 'a' THEN '1' 
            WHEN 'b' THEN '2' 
            ... c -> i
            WHEN 'j' THEN '10' 
            WHEN 'k' THEN '11'  
        END [col] 
    FROM LinkedServer.database.dbo.table
)

Mas um TVF de várias instruções semelhante funciona bem:

ALTER FUNCTION [dbo].[fn_MyFunction]
(   
    @var varchar(20)
)
RETURNS @result TABLE 
(
    value varchar(max)
)
AS
BEGIN
    INSERT INTO @result
    SELECT CASE column 
            WHEN 'a' THEN '1' 
            WHEN 'b' THEN '2' 
            ... c -> i
            WHEN 'j' THEN '10' 
            WHEN 'k' THEN '11'  
        END [col] 
    FROM LinkedServer.database.dbo.table

RETURN;
END
sql-server sql-server-2008
  • 5 5 respostas
  • 22611 Views

5 respostas

  • Voted
  1. Best Answer
    Paul White
    2013-05-23T14:44:44+08:002013-05-23T14:44:44+08:00

    Claramente não há uma CASEexpressão aninhada aqui.

    Não no texto da consulta, não. Mas o analisador sempre expande CASEas expressões para a forma aninhada:

    SELECT CASE SUBSTRING(p.Name, 1, 1)
            WHEN 'a' THEN '1' 
            WHEN 'b' THEN '2' 
            WHEN 'c' THEN '3' 
            WHEN 'd' THEN '4' 
            WHEN 'e' THEN '5' 
            WHEN 'f' THEN '6' 
            WHEN 'g' THEN '7' 
            WHEN 'h' THEN '8' 
            WHEN 'i' THEN '9' 
            WHEN 'j' THEN '10' 
            WHEN 'k' THEN '11'  
        END
    FROM AdventureWorks2012.Production.Product AS p
    

    Plano de consulta local

    Essa consulta é local (sem servidor vinculado) e o Compute Scalar define a seguinte expressão:

    Expressão CASE aninhada

    Isso é bom quando executado localmente, porque o analisador não vê uma CASEinstrução aninhada com mais de 10 níveis de profundidade (embora passe uma para os estágios posteriores da compilação da consulta local).

    No entanto, com um servidor vinculado, o texto gerado pode ser enviado ao servidor remoto para compilação. Se for esse o caso, o analisador remoto vê uma CASEinstrução aninhada com mais de 10 níveis de profundidade e você obtém o erro 8180.

    Outra esquisitice. Esta função com valor de tabela embutida produz o mesmo erro

    A função in-line é expandida no local no texto da consulta original, portanto, não é surpresa que os mesmos resultados de erro ocorram com o servidor vinculado.

    Mas um TVF de várias instruções semelhante funciona bem

    Parecidos, mas não iguais. O msTVF envolve uma conversão implícita para varchar(max), que acontece para evitar que a CASEexpressão seja enviada ao servidor remoto. Como o CASEé avaliado localmente, um analisador nunca vê um excesso de aninhamento CASEe não há erro. Se você alterar a definição da tabela varchar(max)para o tipo implícito do CASEresultado - varchar(2)- a expressão será remota com o msTVF e você receberá um erro.

    Por fim, o erro ocorre quando um over-nested CASEé avaliado pelo servidor remoto. Se o CASEnão for avaliado no iterador de Consulta Remota, não haverá erro. Por exemplo, o seguinte inclui um CONVERTque não é remoto, portanto, nenhum erro ocorre mesmo que um servidor vinculado seja usado:

    SELECT CASE CONVERT(varchar(max), SUBSTRING(p.Name, 1, 1))
            WHEN 'a' THEN '1' 
            WHEN 'b' THEN '2' 
            WHEN 'c' THEN '3' 
            WHEN 'd' THEN '4' 
            WHEN 'e' THEN '5' 
            WHEN 'f' THEN '6' 
            WHEN 'g' THEN '7' 
            WHEN 'h' THEN '8' 
            WHEN 'i' THEN '9' 
            WHEN 'j' THEN '10' 
            WHEN 'k' THEN '11'  
        END
    FROM SQL2K8R2.AdventureWorks.Production.Product AS p
    

    CASO não remoto

    • 25
  2. Aaron Bertrand
    2013-05-23T12:34:10+08:002013-05-23T12:34:10+08:00

    Meu palpite é que a consulta está sendo reescrita em algum lugar ao longo do caminho para ter uma CASEestrutura ligeiramente diferente, por exemplo

    CASE WHEN column = 'a' THEN '1' ELSE CASE WHEN column = 'b' THEN '2' ELSE ...
    

    Acredito que seja um bug em qualquer provedor de servidor vinculado que você esteja usando (na verdade, talvez em todos eles - já vi isso relatado em vários). Eu também acredito que você não deve prender a respiração esperando por uma correção, seja na funcionalidade ou na mensagem de erro confusa explicando o comportamento - isso é relatado há muito tempo, envolve servidores vinculados (que não tiveram muito amor desde o SQL Server 2000) e afeta muito menos pessoas do que esta mensagem de erro confusa , que ainda não foi corrigida após a mesma longevidade.

    Como Paul aponta , o SQL Server está expandindo sua CASEexpressão para a variedade aninhada, e o servidor vinculado não gosta disso. A mensagem de erro é confusa, mas apenas porque a conversão subjacente da expressão não é imediatamente visível (nem intuitiva de forma alguma).

    Uma solução alternativa (além da alteração de função que você adicionou à sua pergunta) seria criar uma exibição ou procedimento armazenado no servidor vinculado e fazer referência a isso, em vez de passar a consulta completa por meio do provedor do servidor vinculado.

    Outro (supondo que sua consulta seja realmente simplista e você queira apenas o coeficiente numérico das letras az) é ter:

    SELECT [col] = RTRIM(ASCII([column])-96)
    FROM LinkedServer.database.dbo.table;
    

    Se você realmente precisa que isso funcione como está, sugiro que entre em contato com o suporte diretamente e abra um caso, embora eu não possa garantir os resultados - eles podem apenas fornecer soluções alternativas às quais você já tem acesso nesta página.

    • 6
  3. Nik
    2014-02-13T05:07:39+08:002014-02-13T05:07:39+08:00

    você pode contornar isso por

    SELECT COALESCE(
    CASE SUBSTRING(p.Name, 1, 1)
        WHEN 'a' THEN '1' 
        WHEN 'b' THEN '2' 
        WHEN 'c' THEN '3' 
        WHEN 'd' THEN '4' 
        WHEN 'e' THEN '5' 
        WHEN 'f' THEN '6' 
        WHEN 'g' THEN '7' 
        WHEN 'h' THEN '8' 
        WHEN 'i' THEN '9' 
        ELSE NULL
    END,
    CASE SUBSTRING(p.Name, 1, 1)
        WHEN 'j' THEN '10' 
        WHEN 'k' THEN '11'  
    END)
    FROM SQL2K8R2.AdventureWorks.Production.Product AS p
    
    • 6
  4. ypercubeᵀᴹ
    2016-06-24T23:35:14+08:002016-06-24T23:35:14+08:00

    Outra solução alternativa para esse problema é usar a lógica baseada em conjunto, substituindo a CASEexpressão por uma junção esquerda (ou aplicação externa) a uma tabela de referência ( refno código abaixo), que pode ser permanente, temporária ou uma tabela/CTE derivada. Se isso for necessário em várias consultas e procedimentos, prefiro ter isso como tabela permanente:

    SELECT ref.result_column AS [col] 
    FROM LinkedServer.database.dbo.table AS t
      LEFT JOIN
        ( VALUES ('a',  '1'),
                 ('b',  '2'), 
                 ('c',  '3'),
                 ---
                 ('j', '10'),
                 ('k', '11')
        ) AS ref (check_col, result_column) 
        ON ref.check_col = t.column ;
    
    • 2
  5. user98586
    2016-06-24T18:36:54+08:002016-06-24T18:36:54+08:00

    uma maneira de contornar isso é incluir o teste na whencláusula, ou seja,

    case
      when SUBSTRING(p.Name, 1, 1) = 'a' THEN '1'
    ...
    
    • -4

relate perguntas

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

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

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

  • Downgrade do SQL Server 2008 para 2005

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • 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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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