loading..
Русский    English
09:17
листать

Упражнение 56 стр. 2

Вот еще одно решение задачи, в котором не используется объединение, но содержится другая ошибка:

Решение 3.12.2

Консоль
Выполнить
  1. SELECT classes.class, COUNT(ship) sunked
  2. FROM Classes FULL JOIN
  3. Ships ON classes.class = ships.class LEFT JOIN
  4. (SELECT ship
  5. FROM Outcomes
  6. WHERE result = 'sunk'
  7. ) s ON s.ship = ships.name OR
  8. s.ship = classes.class
  9. GROUP BY classes.class;

Первое (полное) соединение:

  1. Classes FULL JOIN
  2. Ships ON classes.class = ships.class

будет содержать все возможные классы кораблей. Заметим, что здесь можно было ограничиться левым (LEFT) соединением, так как согласно связи между таблицами в Ships не может быть корабля, класс которого отсутствует в таблице Classes.

Далее выполняется левое соединение с потопленными кораблями из таблицы Outcomes по следующему предикату (множество s содержит все потопленные корабли):

  1. ON s.ship = ships.name OR s.ship = classes.class

То есть мы включаем в результирующий набор корабль, если имя его совпадает с именем потопленного корабля или если класс совпадает с именем потопленного корабля. На рассмотренных выше примерах данных этот запрос будет работать правильно, в отличие от первого рассмотренного решения. Действительно, если в классе «Бисмарк» имеется два потопленных корабля, один из которых является головным и отсутствует в Ships, то оба они будут учтены согласно рассмотренному выше предикату. Если же головной корабль присутствует в таблице Ships, то это ничего не меняет, так как предикат все равно будет выполнен.

В чем же здесь ошибка? Ошибка заключается как раз в предикате последнего соединения. Пусть в таблице Ships имеются корабли некоторого класса (например, два корабля с именами А и В класса Class_1), которые не были потоплены. И пусть в Outcomes имеется потопленный головной корабль этого же класса. Тогда соединяться будут следующие два отношения (приводим здесь только важные для анализа атрибуты):

Class Name
Class_1 A
Class_1 B

и

Ship (отношение s) Class_1

по предикату

s.ship = classes.class

В результате будет получено отношение, содержащее корабли, которые не были потоплены, но учитываются этим решением:

Class Name Ship
Class_1 A Class_1
Class_1 B Class_1

Можно сказать иначе, а именно, потопленный головной корабль учтен здесь столько раз, сколько кораблей этого класса имеется в таблице Ships (как потопленных, так и нет). Так или иначе, но COUNT(ship) = 2, что неверно, так как потоплен был всего один корабль.

Кстати, из сказанного становится очевидным, как исправить данное решение; причем сделать это очень просто. Можно просто добавить 8 символов. Попробуйте.

Bookmark and Share
Страницы: 1 2 3 4 5
Тэги:
ALL AND AUTO_INCREMENT AVG battles CASE CAST CHAR CHARINDEX CHECK classes COALESCE CONSTRAINT Convert COUNT CROSS APPLY CTE DATEADD DATEDIFF DATENAME DATEPART DATETIME DDL DEFAULT DELETE DISTINCT DML EXCEPT EXISTS EXTRACT FOREIGN KEY FROM FULL JOIN GROUP BY Guadalcanal HAVING IDENTITY IN INFORMATION_SCHEMA INNER JOIN insert INTERSECT IS NOT NULL IS NULL ISNULL laptop LEFT LEFT OUTER JOIN LEN maker Больше тэгов
Учебник обновлялся
месяц назад
https://exchangesumo.com/obmen/WEXRUB-QIWIRUB/
©SQL-EX,2008 [Развитие] [Связь] [О проекте] [Ссылки] [Team]
Перепечатка материалов сайта возможна только с разрешения автора.