На главную страницу
Характерные ошибки при решении упражнений.
Задача 43
Моисеенко С.И.
Для каждой страны определить год, когда на воду было спущено максимальное
количество ее кораблей. В случае, если окажется несколько таких лет, взять
минимальный из них. Вывод: страна, количество кораблей, год.
Устав отвечать на вопросы относительно этой задачи, я решил объяснить
допускаемую при ее решении одну и ту же ошибку. Однако чтобы не лишать вас
удовольствия самостоятельно решить эту задачу, упрощу формулировку.
Итак,
Определить год, когда на воду было спущено максимальное количество кораблей.
Вывод: количество кораблей, год.
Определить распределение количества кораблей по годам можно так
SELECT launched [year], COUNT(*) cnt FROM Ships GROUP BY
launched
Теперь нам нужно оставить из всех строк, возвращаемых этим запросом, только те,
у которых количество (cnt) максимально, т.е.
>= ALL(SELECT COUNT(*) cnt FROM Ships GROUP BY launched)
Окончательно получим
SELECT * FROM
(
SELECT launched [year], COUNT(*) cnt FROM Ships GROUP BY launched
) x
WHERE cnt >= ALL(SELECT COUNT(*) cnt FROM Ships GROUP BY launched)
Тем не менее, здесь кроется ошибка. Эта ошибка не связана с формальным
построением решения. Оно не вызывает сомнения. Как это обычно происходит при
решении задач на сайте, ошибка заключается в неточном учете особенностей модели
предметной области, а именно, ее ограничений. В данном случае - это
допустимость того, что в базе данных могут быть корабли с неизвестным годом
спуска на воду. Хочу здесь отметить, что если в описании предметной области не
оговорено противное, неключевые поля допускают NULL-значения. Собственно, по
умолчанию это и имеется в виду, когда мы создаем таблицу с помощью оператора
CREATE TABLE.
Строить корабли - это не кроликов разводить :-). Корабли строятся годами.
Поэтому, если для ряда кораблей год спуска на воду неизвестен (NULL), то велика
вероятность того, что число таких кораблей будет больше, чем количество
кораблей, спущенных на воду в любом реальном году. Особенность группировки
заключается в том (и это оговорено в Стандарте), что NULL-значения трактуются
как РАВНЫЕ. Следовательно, все корабли с неизвестным годом спуска на воду,
будут просуммированы с годом NULL. Я полагаю, что результат не должен включать
такую строку по той причине, что неизвестный год - не значит один и тот же. С
этим можно, конечно, поспорить. Однако все споры сведутся к допустимости
использования специфического значения NULL в реляционной модели. Дискуссии по
этому поводу ведутся со времен создания этой модели Коддом Е.Ф., которому и
принадлежит идея NULL-значения. Однако, насколько мне известно, достойной
альтернативы предложено не было.
Возвращаясь к нашей задаче, я, в знак безграничного уважения к Кодду, внесу в
решение следующее изменение:
SELECT * FROM
(
SELECT launched [year], COUNT(*) cnt FROM Ships
WHERE launched IS NOT NULL
GROUP BY launched
) x
WHERE cnt >= ALL(SELECT COUNT(*) cnt FROM Ships
WHERE launched IS NOT NULL
GROUP BY launched)
Приведенные здесь примеры можно выполнить непосредственно на сайте, установив
флажок "Без проверки" на странице с упражнениями
на SELECT.
Перейти к
решению задачи #43
На главную страницу