loading..
Русский    English
08:32
листать

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

Для каждого класса определите число кораблей этого класса, потопленных в сражениях. Вывести: класс и число потопленных кораблей.

Решение 3.12.1

Консоль
Выполнить
  1. SELECT aa.class, SUM(aa.sunks) Sunks
  2. FROM (
  3. -- 1
  4. SELECT c.class, COUNT(a.ship) sunks
  5. FROM Outcomes a INNER JOIN
  6. Ships b ON a.ship = b.name INNER JOIN
  7. Classes c ON b.class = c.class
  8. WHERE a.result = 'sunk'
  9. GROUP BY c.class
  10. UNION
  11. -- 2
  12. SELECT c.class, COUNT(a.ship)
  13. FROM Outcomes a INNER JOIN
  14. Classes c ON a.ship = c.class
  15. WHERE a.result = 'sunk'
  16. GROUP BY c.class
  17. UNION
  18. -- 3
  19. SELECT c.class, 0
  20. FROM Classes c
  21. ) aa
  22. GROUP BY aa.class;

В подзапросе предложения FROM объединяются три таблицы:

Класс и число потопленных кораблей, которые есть в таблице Ships.

Класс и число потопленных головных кораблей класса. Здесь уже есть «излишество», а именно: нет необходимости использовать группировку и соответственно функцию COUNT, так как у класса может быть только один головной корабль, да и потоплен корабль может быть только однажды.

Каждый класс с нулевым количеством потопленных кораблей. Это позволяет учесть те классы, которые не имеют потопленных кораблей и, следовательно, не попадают в предыдущие два набора записей.

Объединение с использованием UNION устраняет дубликаты, что, по мнению автора решения, позволяет корректно обработать ситуацию, когда потопленный головной корабль присутствует в таблице Ships. Наконец, выполняется группировка по классам с суммированием. При этом последний набор не дает вклада в окончательный результат, если в классе имеются потопленные корабли, что правильно.

Однако ошибка кроется в том, что объединяются двухатрибутные кортежи {класс, число потопленных кораблей}. Поэтому если в некотором классе (опять «Бисмарк») имеется два потопленных корабля, причем головной корабль отсутствует в Ships, то объединяться будут два одинаковых кортежа

Бисмарк 1

Тогда после устранения дубликатов мы получаем один потопленный корабль вместо двух.

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

Бисмарк 2

а второй:

Бисмарк 1

В результате мы получим

Бисмарк 3

хотя на самом деле корабля всего два.

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 Больше тэгов
Учебник обновлялся
месяц назад
©SQL-EX,2008 [Развитие] [Связь] [О проекте] [Ссылки] [Team]
Перепечатка материалов сайта возможна только с разрешения автора.