Упражнение 37 (подсказки и решения)
Рассмотрим следующее решение задачи, которое свободно от уже проанализированных ошибок:
SELECT t1.class
FROM (SELECT a.class AS class, COUNT(b.name) AS coun
FROM Classes a
LEFT JOIN Ships b ON b.class = a.class
GROUP BY a.class
UNION ALL
SELECT a1.class AS class, COUNT(ship) AS coun
FROM Classes a1
LEFT JOIN Outcomes d ON d.ship = a1.class
WHERE d.ship NOT IN (SELECT b.name
FROM Ships b
)
GROUP BY a1.class
) t1
GROUP BY t1.class
HAVING SUM(t1.coun) = 1;
[[ column ]] |
---|
[[ value ]] |
Действительно, в подзапросе объединяются два запроса, первый из которых подсчитывает для каждого класса корабли из таблицы Ships, а второй подсчитывает только те головные корабли, которых нет в Ships. Затем основной запрос для каждого класса эти количества суммирует и оставляет только те классы, в которых содержится только один корабль.
Обратите внимание на использование UNION ALL. Это необходимо, т. к. в противном случае будут устранены дубликаты пары {класс, количество кораблей}, в результате чего будет выводиться класс, для которого имеется один неголовной корабль в Ships и головной в Outcomes. Как раз эта характерная ошибка отмечалась нами ранее.
Что же осталось исправить, раз это решение не принимается системой? Причина ошибки заключается в том, что головной корабль класса может принимать участие в нескольких сражениях, и тогда второй из объединяемых запросов столько раз учтет один и тот же головной корабль, сколько раз тот участвовал в сражениях.