Pergunta

Eu tenho uma instrução que seleciona a substring de um charindex da seguinte forma:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5

Quando executo a instrução acima em uma consulta selecionada, os resultados são retornados perfeitamente.Quando executo a instrução acima em uma visualização indexada vinculada ao esquema, recebo este erro:

Invalid length parameter passed to the LEFT or SUBSTRING function

Para resolver o problema escreverei uma função para obter o Max do CharIndex e 0 para remover as possibilidades de um valor negativo.Mas alguém sabe por que a cláusula where não estaria filtrando a instrução select?

Foi útil?

Solução

Porque a ordem das operações nos bastidores de uma consulta não é garantida.

Suponho que se você verificar o plano de execução, verá que ele está fazendo as duas verificações em paralelo - isso porque nenhuma operação pode usar um índice!

De qualquer maneira, o SQL precisa carregar todas as linhas desse campo na memória, portanto, está processando-o para os dois critérios ao mesmo tempo.

Podes tentar WITH (MAXDOP(1)) como uma dica de consulta para ver se isso evita que o problema apareça ou você pode fazer uma subseleção para forçar a ordem de execução:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
      SELECT Stringfield 
      FROM Table 
      WHERE CHARINDEX('ABC', StringField) > 5
      ) as [X]

Eu tive um problema semelhante uma vez quando estava verificando se um campo era numérico usando PATINDEX e uma das colunas na minha opinião estava convertendo isso em um int - Recebi erros de conversão porque o mecanismo estava convertendo todas as linhas, pois meus filtros não eram SARGable.

Outras dicas

Esta é uma solução alternativa feia, mas você poderia fazer algo assim:

DECLARE @x TABLE(StringField VARCHAR(32));

INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

SELECT SUBSTRING(StringField,
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
    CHARINDEX('ABC', StringField) - 
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

Ambos rendem:

---
AAA

Mas suspeito que o último será permitido na sua opinião.É feio, mas infelizmente, a menos que você primeiro despeje os dados filtrados em uma tabela #temp (ou tente ver se MAXDOP remove o problema de forma confiável), você não terá muito controle sobre a ordem de processamento.

Outra idéia é tentar colocar uma coluna computada na tabela (mas não tenho certeza se isso ajudará se você estiver tentando criar uma visualização indexada - ainda pode haver complicações).Ou usar um índice filtrado com essa expressão, em vez de uma visualização indexada.Pode haver várias "soluções" se soubermos o que a visualização indexada pretende realizar e qual versão do SQL Server você está usando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top