Упражнение 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;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]

Действительно, в подзапросе объединяются два запроса, первый из которых подсчитывает для каждого класса корабли из таблицы Ships, а второй подсчитывает только те головные корабли, которых нет в Ships. Затем основной запрос для каждого класса эти количества суммирует и оставляет только те классы, в которых содержится только один корабль.

Обратите внимание на использование UNION ALL. Это необходимо, т. к. в противном случае будут устранены дубликаты пары {класс, количество кораблей}, в результате чего будет выводиться класс, для которого имеется один неголовной корабль в Ships и головной в Outcomes. Как раз эта характерная ошибка отмечалась нами ранее.

Что же осталось исправить, раз это решение не принимается системой? Причина ошибки заключается в том, что головной корабль класса может принимать участие в нескольких сражениях, и тогда второй из объединяемых запросов столько раз учтет один и тот же головной корабль, сколько раз тот участвовал в сражениях.

Вернуться к обсуждению упражнения 37

Решить задачу на SQL-EX.RU