На главную страницу
Характерные ошибки при решении упражнений.
Задача 35
Моисеенко С.И.
Укажите названия, водоизмещение и число орудий, кораблей участвовавших в сражении
при Гвадалканале (Guadalcanal).
Почему система не принимает следующее решение:
SELECT o.Ship, c.displacement, c.numGuns
FROM outcomes o
LEFT JOIN Ships s ON o.ship=s.Name
LEFT JOIN classes c ON s.class=c.Class
LEFT JOIN battles b ON b.Name=o.Battle
WHERE (b.Name='Guadalcanal')
На первый взгляд все верно. Соединение с отбором
outcomes o
LEFT JOIN battles b ON b.Name=o.Battle
...
WHERE ( b.Name=' Guadalcanal ')
дает нам все корабли, участвовавшие в сражении при Гвадалканале . Далее ,
LEFT JOIN Ships s ON o.ship=s.Name
LEFT JOIN classes c ON s.class=c.Class
соединение с таблицей Ships позволяет узнать класс корабля, а соединение Ships и
Classes позволяет узнать требуемые характеристики корабля. При этом левое
соединение гарантирует появление корабля в выходном наборе даже в том случае,
если его класс неизвестен (корабля нет в Ships или есть, но неизвестен его
класс - NULL; хотя последнее
в нашей схеме запрещено ограничением NOT NULL на столбце Ships.class). В последнем случае будет получена строка типа:
Корабль NULL NULL
Ошибка заключается в пресловутом "Бисмарке". Не в нем именно, в той ситуации,
когда в Outcomes имеется головной корабль, которого нет в Ships . Предположим,
что "Бисмарк" был при Гвадалканале . Рассматриваемый нами запрос вернет такую
строку:
Bismarck NULL NULL
т.к. этого корабля нет в Ships . Однако его характеристики нам известны,
поскольку известен класс (головной корабль!). Правильной строкой будет:
Bismarck 8 42000
Строку же
Корабль NULL NULL
мы получаем только в том случае, если в битве принимал участие не головной
корабль, отсутствующий в таблице Ships (или при неизвестном классе).
Вот такой корабль:
INSERT INTO outcomes VALUES('Kyoto','Guadalcanal','ok')
Перейти к
решению задачи #35
На главную страницу