¿Cómo fuerzo a SQL Server 2005 a ejecutar una unión antes de dónde?
-
10-07-2019 - |
Pregunta
Tengo una consulta SQL que une una tabla de precios a una tabla que contiene respuestas proporcionadas por el usuario. Mi consulta se utiliza para obtener el precio en función de la cantidad ingresada. A continuación se muestra mi declaración SQL:
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
WHERE Price.Min <= JobQuestion.Value
AND Price.Max >= JobQuestion.Value
El problema es que SQL Server ejecuta la cláusula where antes de JOIN y arroja el error:
La conversión falló al convertir el valor varchar 'PRUEBA' para el tipo de datos int.
porque está haciendo las comparaciones mínimas y máximas antes de la unión ('PRUEBA' es un valor válido ingresado por el usuario en la tabla JobQuestion, pero no debe devolverse cuando JobQuestion se une a Price). Creo que SQL Server está eligiendo ejecutar WHERE porque, por alguna razón, el analizador cree que sería una consulta más eficiente. Si solo corro
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
Obtengo estos resultados:
500 1 500 272.00
500 501 1000 442.00
500 1001 2000 782.00
Entonces, agregar WHERE debería filtrar los dos últimos y simplemente devolver el primer registro. ¿Cómo fuerzo a SQL a ejecutar JOIN primero o utilizo otra técnica para filtrar solo los registros que necesito?
Solución
Primero, este es un signo muy probable de diseño deficiente.
Si no puede cambiar el esquema, entonces tal vez podría forzar este comportamiento utilizando sugerencias . Cita:
Las sugerencias son opciones o estrategias especificadas para la aplicación por parte del procesador de consultas de SQL Server en las instrucciones SELECT, INSERT, UPDATE o DELETE. Las sugerencias anulan cualquier plan de ejecución que el optimizador de consultas pueda seleccionar para una consulta.
Y algo más:
Precaución:
Debido a que el optimizador de consultas de SQL Server generalmente selecciona el mejor plan de ejecución para una consulta, recomendamos que & Lt; join_hint > ;, < query_hint > ;, y < table_hint > ser utilizado solo como último recurso por desarrolladores experimentados y administradores de bases de datos.
Otros consejos
Pruebe " reformulando " la consulta de la siguiente manera:
SELECT *
FROM (
SELECT JobQuestion.Value,
Price.Min,
Price.Max,
Price.Amount
FROM Price
INNER
JOIN JobQuestion
ON Price.QuestionFK = JobQuestion.QuestionFK
AND JobQuestion.JobFK = 1
) SQ
WHERE SQ.Min <= SQ.Value
AND SQ.Max >= SQ.Value
Según la respuesta de Christian Hayter, si tiene la opción, cambie el diseño de la tabla =)
No deberías comparar cadenas con ints. Si tiene alguna influencia sobre el diseño de su tabla, divida los dos usos diferentes de la columna JobQuestion.Value
en dos columnas diferentes.
En caso de que no tenga influencia sobre el diseño de su tabla, ¿podría intentar filtrar esos registros con valores numéricos usando ISNUMERIC ()? Supongo que agregar esto a su cláusula where podría ayudar.
Es probable que pueda eliminar el where ... y simplemente agregarlos como predicados a su unión. Como es una unión interna, esto debería funcionar
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount
FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
AND Price.Min <= JobQuestion.Value
AND Price.Max >= JobQuestion.Value
Puede usar TRY_PARSE sobre esas columnas de cadenas para convertir a numérico, y si SQL no puede convertir, obtendrá NULL en lugar de mensaje de error.
P.S. Esto se introdujo por primera vez en SQL 2012, por lo que podría ser útil.