loading..
Русский    English
02:46
листать

Упражнение (-2) стр. 2

Чтобы исправить эту ошибку, недостаточно убрать из группировки столбец launched:

Консоль
Выполнить
  1. SELECT MIN(launched)
  2. FROM Ships aa, Classes bb
  3. WHERE bb.class = aa.class
  4. GROUP BY country;

в результате чего будут получены минимальные годы по каждой стране:

1916
1913
1920

Тогда строки, удовлетворяющие предикату, будут выглядеть так:

country x launched
Gt.Britain 6 1916
Japan 1 1913
Japan 1 1916
USA 1 1920

Таким образом, мы уже потеряли правильные строки для Японии и США. Следует обратить внимание еще и на то, что мы получили строку для Японии:

Japan 1 1916
только на основании того, что год 1916 совпал с минимальным годом для США. Дальнейший код не имеет смысла. Однако и там имеется принципиальная ошибка. В основном запросе

  1. SELECT country, MAX(x), MIN(launched)
  2. GROUP BY country
выполняется группировка по стране с определением двух агрегатных показателей — максимума по количеству кораблей и минимума по году. Использование в данном случае группировки ошибочно. Действительно, нужные нам строки уже находятся в таблице, получаемой в предложении FROM (например, строка {Gt.Britain, 6, 1916}). Зачем же здесь группировка, когда требуется лишь критерий, который поставит фильтр, отсекающий лишние строки. В результате же группировки образуется одна строка, содержащая статистические показатели для всей группы. При этом максимум и минимум в общем случае достигаются в разных строках группы. Это хорошо видно из таблицы на примере кораблей США, когда минимальному году отвечает далеко не максимальное значение (x=1), а максимальное значение (x=3) достигается совсем в другом году (1941). Поэтому такая группировка может дать правильный результат (в смысле условия задачи) только в том случае, если все значения x для страны совпадают.

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

Чтобы все же связать год со страной, можно использовать коррелирующий подзапрос в предложении WHERE (AND aa.country = s.country):

  1. WHERE launched = ANY(SELECT MIN(launched)
  2. FROM Ships bb, Classes aa
  3. WHERE aa.class = bb.class AND
  4. aa.country = s.country
  5. GROUP BY country
  6. )

Это правильно, но пока ничего не меняет, разве что исключит неправильную строку:

Japan 1 1916

Чтобы двигаться дальше, нужно вычислять минимальный год среди лет с максимальным количеством кораблей для каждой страны. Здесь первичным является максимальное количество кораблей. Ведь выбирая лишь минимальный год, мы можем потерять правильные строки. Поэтому в предикате нужно оценивать не год, а количество кораблей:

  1. WHERE x >= ALL(SELECT COUNT(launched)
  2. FROM Ships bb, Classes aa
  3. WHERE bb.class = aa.class AND
  4. s.country=aa.country
  5. GROUP BY country, launched
  6. )

Обратите внимание на предикат >= ALL — (больше или равно), который дает нам максимальное значение x. Перепишем весь запрос с учетом сказанного о группировке в основном запросе:

Решение 3.6.2

Консоль
Выполнить
  1. SELECT country, x, launched
  2. FROM (SELECT country, COUNT(*) x , launched
  3. FROM Ships b, Classes a
  4. WHERE a.class = b.class
  5. GROUP BY country, launched
  6. ) s
  7. WHERE x >= ALL(SELECT COUNT(launched)
  8. FROM Ships bb, Classes aa
  9. WHERE bb.class = aa.class AND
  10. s.country=aa.country
  11. GROUP BY country, launched
  12. );

Все? Не совсем. Если максимум для какой-нибудь страны достигается в разные годы, то мы получим по строке на каждый год. Нам же по условиям задачи требуется в таком случае вывести минимальный год. Как было отмечено выше, это как раз тот самый случай, когда группировка приемлема по смыслу (все значения x для страны одинаковы — максимальны):

Bookmark and Share
Страницы: 1 2 3 4
Тэги:
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/CNTEUR-NIXEUR/
©SQL-EX,2008 [Развитие] [Связь] [О проекте] [Ссылки] [Team]
Перепечатка материалов сайта возможна только с разрешения автора.