Pregunta

Tengo una declaración de que selecciona la subcadena de una charindex de la siguiente manera:

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

Al ejecutar la instrucción anterior en una consulta de selección, los resultados se devuelven bien.Al ejecutar la instrucción anterior en un esquema obligado vista indizada, me sale este error:

Invalid length parameter passed to the LEFT or SUBSTRING function

Para resolver el problema, voy a escribir una función para obtener el máximo de la CharIndex y 0 para eliminar las posibilidades de un valor negativo.Pero ¿alguien sabe por qué la cláusula where no sería el filtrado de la instrucción select?

¿Fue útil?

Solución

Porque el orden de las operaciones detrás de las escenas en una consulta no está garantizada.

Supongo que si consulta el plan de ejecución, verá que está haciendo ambas verificaciones en paralelo, ¡esto porque ninguna operación puede usar un índice!

SQL necesita cargar cada fila de ese campo en la memoria de todos modos, por lo que lo está procesando para ambos criterios al mismo tiempo.

Puede intentarlo WITH (MAXDOP(1)) como una sugerencia de consulta para ver si sigue apareciendo el problema, o podría hacer una subselección para forzar el orden de ejecución:

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

Tuve un problema similar una vez cuando estaba comprobando si un campo era numérico usando PATINDEX y una de las columnas en mi opinión estaba convirtiendo esto a un int, tengo errores de conversión porque el motor estaba convirtiendo cada fila desde miLos filtros no fueron sargables.

Otros consejos

Este es un feo solución, pero se podría hacer algo como esto tal vez:

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;

Tanto el rendimiento:

---
AAA

Pero sospecho que el último será permitido en su punto de vista.Es feo, pero por desgracia, a menos que el volcado de los datos filtrados en una tabla #temp primera (o a probar a ver si MAXDOP elimina de forma fiable el tema), no vas a tener mucho control sobre el orden de procesamiento.

Otra idea es tratar de poner una columna calculada en la tabla (pero no estoy seguro de que le ayudará si usted está tratando de crear una vista indizada - todavía puede haber complicaciones).O el uso de un índice filtrado con esa expresión, en lugar de una vista indizada.Podría haber varias "soluciones" si sabemos lo que la vista indizada es el propósito de lograr y qué versión de SQL Server que está utilizando.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top