Обсуждение
В заметке сделана попытка показать, что запросы с разделами GROUP BY и HAVING (GBH-запросы) и переменные с областью значений являются избыточными в языке SQL. Интересно заметить, что эти аспекты SQL относятся к числу тех, которые наиболее трудно изучаются, понимаются и правильно применяются. Если говорить конкретно о GBH-запросах, то кажется, что альтернативные формулировки часто бывают более предпочтительными. Рассмотрим еще раз запрос Q4 из первой части заметки.
Q4: Выдать номер каждой детали, поставляемой более чем одним поставщиком.
Вот формулировки этого запроса с GBH и без GBH:
SELECT SP.P# FROM SP GROUP BY SP.P# HAVING COUNT(*) > 1 ;
SELECT DISTINCT SP.P# FROM SP WHERE ( SELECT COUNT(*) FROM SP AS SPX WHERE SPX.P# = SP.P# ) > 1 ;
По мнению Дейта,
- Вариант без GBH по крайней мере логически понятнее и проще чем вариант с GBH, поскольку в нем не используются дополнительные языковые конструкции (разделы GROUP BY и HAVING)
- Из исходной формулировки проблемы не видно, что именно группирование требуется для выражения запроса на SQL (и оно действительно не требуется)
- Далеко не очевидно, что нужен раздел HAVING, а не раздел WHERE
Вариант с GBH больше похож на предписание решения проблемы, т.е. набора шагов, которые необходимо предпринять для нахождения ответа, а не на описание самой проблемы. А общее назначение реляционной модели всегда состояло в том, чтобы можно было использовать декларативные, а не процедурные формулировки. Декларативные формулировки требуют работы системы, процедурные - работы пользователя.
Конечно, нельзя отрицать, что вариант формулировки с GBH более короткий. Но если единственным преимуществом формулировок с GBH является краткость, то было бы лучше определять такие формулировки как сокращенную запись. Тогда, вероятно, не проявлялись бы отмеченные в заметке аномалии и реализация была бы проще. Замечание: следует упомянуть, что реляционный аналог разделов GROUP BY и HAVING языка SQL оператор SUMMARIZE определяется как сокращенная запись.
Наконец, необходимо отметить, что язык SQL содержит много других избыточностей (например, оператор EXISTS абсолютно избыточен). В результате большинство тривиальных запросов может быть выражено на языке SQL массой различных способов. Даже такой простой запрос как "Выдать имена поставщиков, которые поставляют деталь P2" можно выразить по меньшей мере восемью разными на вид способами. (И это при том условии, что используются только возможности SQL-86! Если применять новые возможности SQL-92, число допустимых формулировок значительно увеличится.)
Почему это положение дел нежелательно? Прежде всего, подобные избыточности делают язык большим, чем требуется, с очевидными последствиями для документирования, реализации, обучения и т.д. В частности, возможность формулировать один и тот же запрос многими разными способами часто вынуждает пользователей тратить время и усилия на поиск лучшей формулировки (под "лучшей" имеется в виду формулировка, которая лучше всего выполняется), а цель реляционной модели заключается в том, чтобы избегать подобной потребности.
Конечно, эта критика не была бы справедливой, если бы все формулировки выполнялись одинаково хорошо, но эта возможность сомнительна. (Сомнительно, чтобы оптимизатор запросов смог работать настолько хорошо.) Конечно, избыточности усложняют реализацию SQL. И особенно странно, что люди, ответственные за разработку языка SQL, большей частью являются представителями компаний-поставщиков СУБД, которые должны обеспечивать реализацию языка.
В заключение заметим, что проблемы избыточности устранить непросто. Если в язык когда-либо была внедрена некоторая возможность, ее никогда уже нельзя удалить, иначе перестанут работать существующие программы. Вот почему так важно иметь правильный язык с самого начала. И в этом основная сложность разработки языка.