Как мне заставить SQL Server 2005 выполнить соединение перед where?
-
10-07-2019 - |
Вопрос
У меня есть SQL-запрос, который соединяет таблицу цен с таблицей, содержащей предоставленные пользователем ответы.Мой запрос используется для получения цены на основе введенного количества.Ниже приведен мой 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
Проблема в том, что SQL Server запускает предложение where перед СОЕДИНЕНИЕМ, и оно выдает ошибку:
Сбой преобразования при преобразовании значения переменной 'TEST' varchar в тип данных int.
потому что он выполняет сравнения min и max перед объединением ('TEST' - это допустимое значение, введенное пользователем в таблице JobQuestion, но не должно быть возвращено при соединении JobQuestion с Price).Я полагаю, что SQL Server выбирает для запуска WHERE, потому что по какой-то причине анализатор считает, что это был бы более эффективный запрос.Если я Просто убегу
SELECT JobQuestion.Value, Price.Min, Price.Max, Price.Amount FROM Price
INNER JOIN JobQuestion
ON Price.QuestionFK=JobQuestion.QuestionFK
AND JobQuestion.JobFK=1
Я получаю эти результаты обратно:
500 1 500 272.00
500 501 1000 442.00
500 1001 2000 782.00
Итак, добавление WHERE должно отфильтровать последние два и просто вернуть первую запись.Как мне заставить SQL сначала запустить СОЕДИНЕНИЕ или использовать другой метод, чтобы отфильтровать только те записи, которые мне нужны?
Решение
Во-первых, это очень вероятный признак плохого дизайна.
Если вы не можете изменить схему, возможно, вы могли бы принудительно применить это поведение, используя подсказки . Цитата:
Подсказки - это параметры или стратегии, указанные для применения процессором запросов SQL Server в инструкциях SELECT, INSERT, UPDATE или DELETE. Подсказки переопределяют любой план выполнения, который оптимизатор запросов может выбрать для запроса.
И еще немного:
Внимание:
Поскольку оптимизатор запросов SQL Server обычно выбирает лучший план выполнения для запроса, мы рекомендуем & Lt; join_hint > ;, < query_hint > и < table_hint GT &; использовать в качестве крайней меры опытные разработчики и администраторы баз данных.
Другие советы
Попробуйте " перефразируйте " запрос выглядит следующим образом:
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
Согласно ответу Кристиана Хейтера, если у вас есть выбор, измените дизайн таблицы =)
Вы не должны сравнивать строки с целыми числами. Если у вас есть какое-либо влияние на дизайн таблицы, разделите два различных использования столбца JobQuestion.Value
на два различных столбца.
Если вы не имеете никакого влияния на дизайн таблицы - не могли бы вы отфильтровать эти записи с помощью числовых значений, используя ISNUMERIC ()? Я думаю, что добавление этого к вашему предложению where может помочь.
Скорее всего, вы можете удалить where ... и просто добавить их в качестве предикатов в ваше объединение. Так как это внутреннее соединение, это должно работать
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
Вы можете использовать TRY_PARSE для преобразования столбцов strings в числовые, и если SQL не сможет преобразовать, он выдаст вам NULL вместо сообщения об ошибке.
P.S.Эта вещь впервые представлена в SQL 2012, так что может быть полезной.