Por que essa CASE
expressã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 CASE
expressã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
Não no texto da consulta, não. Mas o analisador sempre expande
CASE
as expressões para a forma aninhada:Essa consulta é local (sem servidor vinculado) e o Compute Scalar define a seguinte expressão:
Isso é bom quando executado localmente, porque o analisador não vê uma
CASE
instruçã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
CASE
instrução aninhada com mais de 10 níveis de profundidade e você obtém o erro 8180.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.
Parecidos, mas não iguais. O msTVF envolve uma conversão implícita para
varchar(max)
, que acontece para evitar que aCASE
expressão seja enviada ao servidor remoto. Como oCASE
é avaliado localmente, um analisador nunca vê um excesso de aninhamentoCASE
e não há erro. Se você alterar a definição da tabelavarchar(max)
para o tipo implícito doCASE
resultado -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 oCASE
não for avaliado no iterador de Consulta Remota, não haverá erro. Por exemplo, o seguinte inclui umCONVERT
que não é remoto, portanto, nenhum erro ocorre mesmo que um servidor vinculado seja usado:Meu palpite é que a consulta está sendo reescrita em algum lugar ao longo do caminho para ter uma
CASE
estrutura ligeiramente diferente, por exemploAcredito 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
CASE
expressã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:
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.
você pode contornar isso por
Outra solução alternativa para esse problema é usar a lógica baseada em conjunto, substituindo a
CASE
expressão por uma junção esquerda (ou aplicação externa) a uma tabela de referência (ref
no 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:uma maneira de contornar isso é incluir o teste na
when
cláusula, ou seja,