loading..
Русский    English
11:49
листать

Упражнение 57 (подсказки и решения)

Ниже представлено решение, в котором правильно определяется число потопленных кораблей (хотя, на наш взгляд, весьма громоздко), однако неправильно подсчитывается общее число кораблей в классе.

Консоль
Выполнить
  1. SELECT f.class, SUM(count_out) AS cnt
  2. FROM (SELECT t.class, SUM(cnt) AS count_out
  3.       FROM (SELECT c.class, ship, COUNT(*) CNT
  4.             FROM Classes c LEFT JOIN
  5.                  Ships s ON c.class = s.class INNER JOIN
  6.                  Outcomes o ON o.ship = s.name AND
  7.                                result = 'sunk'
  8.             GROUP BY c.class,ship
  9.             ) AS t
  10.      GROUP BY t.class
  11.      UNION ALL
  12.      SELECT t.class, SUM(cnt) AS count_out
  13.      FROM (SELECT c.class, ship, COUNT(*) cnt
  14.            FROM Classes c INNER JOIN
  15.                 Outcomes o ON c.class = o.ship AND
  16.                               o.result = 'sunk' AND
  17.                               NOT EXISTS (SELECT *
  18.                                           FROM Ships
  19.                                           WHERE o.ship = name
  20.                                           )
  21.            GROUP BY c.class,ship
  22.            ) AS t
  23.      GROUP BY t.class
  24.      ) AS f
  25. GROUP BY f.class
  26. HAVING 2 < (SELECT SUM(cnt)
  27.             FROM (SELECT COUNT(c.class) AS cnt
  28.                   FROM Classes c, Ships s
  29.                   WHERE c.class = s.class AND
  30.                         c.class = f.class
  31.                   UNION
  32.                   SELECT COUNT(c.class) AS cnt
  33.                   FROM Classes c, Outcomes o
  34.                   WHERE c.class = o.ship AND
  35.                         c.class = f.class AND
  36.                         NOT EXISTS (SELECT *
  37.                                     FROM Ships
  38.                                     WHERE o.ship = name
  39.                                     )
  40.                   ) AS k
  41.             );

Подсчет общего числа кораблей в классе выполняется здесь в предложении HAVING основного запроса. В подзапросе этого предложения для каждого класса из основного запроса выполняется объединение числа кораблей из таблицы Ships с числом кораблей (головных) из таблицы Outcomes при условии, что такие корабли не были учтены ранее (их нет в таблице Ships).

Видно, что поскольку объединяются одноатрибутные отношения посредством оператора UNION, то если у нас имеется по одному кораблю и в одном, и другом наборе, мы заведомо получаем неверный результат в результате устранения дубликатов. Однако здесь это как бы не должно являться ошибкой, так как мы отбираем классы, имеющие в сумме более двух кораблей. А других возможных вариантов быть не должно, поскольку головной корабль если и есть, то он только один (несмотря на излишнее использование COUNT во втором запросе). И все же ошибка кроется именно здесь. Дело в том, что если головной корабль принимал участие более чем в одном сражении, то мы его учитываем по числу сражений, разумеется, если его нет в таблице Ships.

Исправить это решение несложно, предлагаем вам сделать это самостоятельно. Однако можно написать и более простой (а также более эффективный) запрос.

Перейти к обсуждению задачи 57

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


Bookmark and Share
Тэги:
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]
Перепечатка материалов сайта возможна только с разрешения автора.