Упражнение 46 (подсказки и решения)
Обещанный пример автоматического соединения двух решений, каждое из которых правильно учитывает один из двух моментов, вызывающих характерные ошибки, может выглядеть так (смотрите комментарии)
-- Корабли, участвующие в битве при Гвадалканале и которые есть в Ships
-- Обратите внимание на использование коррелирующего подзапроса в
-- предложении WHERE, который решает проблему устранения дубликатов при
-- декартовом произведения
SELECT a.ship, displacement, numGuns
FROM (SELECT ship
FROM Outcomes
WHERE battle = 'Guadalcanal'
) AS a, Classes
WHERE class IN (SELECT class
FROM Ships
WHERE name = a.ship
)
UNION
-- Аналогичный по логике запрос, который выбирает те головные корабли из
-- Outcomes, которые сражались при Гвадалканале.
SELECT a.ship, displacement, numGuns
FROM (SELECT ship
FROM Outcomes
WHERE battle = 'Guadalcanal'
) AS a, Classes
WHERE class IN (SELECT ship
FROM Outcomes
WHERE ship = a.ship
)
UNION
--По сути, это решение 3.1.1
SELECT a.ship, displacement, numGuns
FROM (SELECT ship
FROM Outcomes
WHERE battle = 'Guadalcanal'
) AS a
LEFT JOIN Classes ON a.ship = class;
[[ column ]] |
---|
[[ value ]] |
В результате получим лишние строки, характерным примером которых являются такие:
ship | displacement | numGuns |
---|---|---|
California | 32000 | 12 |
California | NULL | NULL |
Можно еще утяжелить этот запрос (и сделать его менее эффективным), добавив код для исключения ошибочной строки. Критерием здесь может служить присутствие NULL-значения, например, в столбце displacement, если есть другая строка с тем же именем корабля. Однако мы советуем обойтись без этого и решить задачу иначе. Тем более, что это возможно, в чем легко убедиться, зайдя на форум сайта, посвященный этой задаче.
В заключение приведем почти правильное решение:
SELECT name, displacement, numGuns
FROM Classes, Ships
WHERE Classes.class = Ships.class
AND name IN (SELECT Ship
FROM Outcomes
WHERE battle = 'Guadalcanal'
)
UNION
SELECT class, displacement, numGuns
FROM Classes
WHERE class IN(SELECT ship
FROM Outcomes
WHERE battle = 'Guadalcanal'
);
[[ column ]] |
---|
[[ value ]] |
Первый запрос из объединения в этом решении находит информацию о кораблях, которые есть в таблице Ships и которые принимали участие в сражение при Гвадалканале.
Второй запрос находит нужные нам головные корабли в Outcomes. Возможные дубликаты (когда головной корабль имеется также и в таблице Ships) исключаются использованием предложения UNION.
Так что же здесь неверно? Если до сих пор непонятно, вернитесь к обсуждению задачи.