Доброго времени суток.
Я сравнительно давно пользуюсь SQL для доступа и обработки данных, и мне всегда было интересно как SQL обрабатывается интерпритатором. Т.е. мне было интересно что происходит "под капотом". Возьмем оператор SELECT. Все кто хоть что-то читал про работу серверов БД с поддержкой SQL знают, что запросы не просто интерпретируются и исполняются,а еще и генерируются планы выполнения, которые проходят ряд проверок и оптимизаций перед тем как результат возвращается запустившему запрос процессу. Это знают все, но не все знают что это такое и как оно работает в действительности. Про планы выполнения и оптимизацию я постараюсь вспомнить чуть позже, в другой статье. Здесь речь пойдет о последовательности выполнения оператора SELECT.
Итак, для примера возьмем запрос к таблицам моей рабочей БД.
SELECT name, COUNT(*) as cnt
FROM dbo.orderitem
WHERE parentid IS NULL
GROUP BY name
HAVING COUNT(*) > 1
ORDER BY name
Этот запрос возвращает наименования заказов количество позиций в которых превышают единицу.
После запуска запроса SQL иинтерпритатор обрабатывает представленный выше запрос не той последовательности в которой он написан, а в несколько иной:
- FROM dbo.orderitem
- WHERE parentid is null
- GROUP BY name
- HAVING COUNT(*) > 1
- SELECT name, COUNT(*) as cnt
- ORDER BY name
Именно в такой последовательности исполняются однотабличные запросы SELECT. Такая последовательность объясняет появления ошибки в случаях, если мы, например, в предложении WHERE захотим использовать псевдоним поля указанный в блоке SELECT.
SELECT name, COUNT(*) as cnt
FROM dbo.orderitem
WHERE parentid IS NULL
AND cnt <> 0 --ОШИБКА! Поля cnt в таблице не существует
GROUP BY name
HAVING COUNT(*) > 1
ORDER BY name
Ошибка сгенерится потому, что часть WHERE исполняется ранее чем SELECT, и на момент выполнения блок WHERE еще ничего не знает о псевдонимах предоставляемых блоком SELECT.
Комментариев нет:
Отправить комментарий