Чи можу я зробити максимум (кол (*)) в SQL?


76

Ось мій код:

    select yr,count(*)  from movie
join casting on casting.movieid=movie.id
join actor on casting.actorid = actor.id
where actor.name = 'John Travolta'
group by yr

Ось питання

Які були найзайнятіші роки для «Джона Траволти». Покажіть кількість фільмів, які він зняв за кожен рік.

Ось структура таблиці:

movie(id, title, yr, score, votes, director)
actor(id, name)
casting(movieid, actorid, ord)

Це результат, який я отримую:

yr  count(*)
1976    1
1977    1
1978    1
1981    1
1994    1
etcetc

Мені потрібно отримати рядки, для яких count(*)макс.

Як це зробити?


1
Питання не розкриває СУБД та версію. Відповідь дуже залежить від цього.
Ервін Брандштеттер

Розумний (і , ймовірно , самий швидкий відповідь ж / оа підзапит) є тут : Використання , LIMIT 1щоб уникнути підзапит.
kaiser

Відповіді:


95

Використання:

  SELECT m.yr, 
         COUNT(*) AS num_movies
    FROM MOVIE m
    JOIN CASTING c ON c.movieid = m.id
    JOIN ACTOR a ON a.id = c.actorid
                AND a.name = 'John Travolta'
GROUP BY m.yr
ORDER BY num_movies DESC, m.yr DESC

Впорядкувавши за num_movies DESC, найвищі значення будуть розміщені у верхній частині набору результатів. Якщо численні роки мають однакову кількість, m.yrнайновіший рік буде розміщений на вершині ... до зміни наступного num_moviesзначення.

Чи можу я використовувати MAX (COUNT (*))?


Ні, ви не можете накладати агрегатні функції одна на одну в одному і тому ж реченні SELECT. Внутрішній агрегат повинен бути виконаний у підзапиті. IE:

SELECT MAX(y.num)
  FROM (SELECT COUNT(*) AS num
          FROM TABLE x) y

3
Так, ви можете використовувати MAX (COUNT (*)), але в Oracle. techonthenet.com/sql/max.php
Андрейс

1
@OMG Ponies - Ця відповідь ДІЙСНО була чудовою - перший SQL, який ви надали, справді працює (obvs) АЛЕ другий SQL, який ви надали, такий дуже елегантний І дозволив мені також краще зрозуміти підзапити! ДЯКУЄМО за те, що ви постаралися дати повністю розширену відповідь. Я намагався досягти цього - але, маючи там також Групу, - і це зробило це цілком можливим!
kiltannen

1
Просто намагаючись зрозуміти це далі - Як би ви використали цей другий запит, щоб отримати рік, в якому було максимальне число фільмів? На даний момент він може визначити, скільки фільмів сталося за рік, в якому було найбільше фільмів, - але це не вказує, який це був рік. Мені б дуже хотілося зрозуміти, як повернути друге значення назад із підзапиту, яке є значенням Group By, співвіднесеним з результатом MAX
kiltannen

це не буде працювати після включення 5.7
Yazgan

28

Просто замовляйте, count(*) descі ви отримаєте найвищу (якщо поєднати з limit 1)


7
А що, якби у мене було кілька рядків з максимальним значенням і я хотів би відобразити всі значення, які мають "максимальне значення"
Адам,

@WhyCry: Не зовсім впевнений, що ти намагаєшся запитати це, але якщо ти не можеш знайти відповідь на Stackoverflow, ти повинен просто задати це як окреме питання :)
Wolph

@Wolph hes каже, що ви можете мати кілька рядків з однаковим максимальним значенням, з обмеженням 1 ви цього не бачите
urSus

Після перечитання цього (3-річного) коментаря, я думаю, він шукаєHAVING MAX(...) = ...
Вольфа,

7
SELECT * from 
(
SELECT yr as YEAR, COUNT(title) as TCOUNT
FROM actor
JOIN casting ON actor.id = casting.actorid
JOIN movie ON casting.movieid = movie.id
WHERE name = 'John Travolta'
GROUP BY yr
order by TCOUNT desc
) res
where rownum < 2

ЗАМОВИТИ БЕЗ ОБМЕЖЕННЯ / ТОП у підзапиті не впливає.
Філіпсія

5

Це питання старий, але посилання в новому питанні про dba.SE . Я відчуваю, що поки що найкращих рішень не надано, тому я додаю ще одне.

По- перше, за умови посилальної цілісності ( як правило , з справлянням зовнішнього ключа) вам не потрібно , щоб приєднатися до столу на всіх . Це мертвий вантаж у вашому запиті. Усі відповіді поки що не вказують на це.movie


Чи можу я зробити max(count(*))в SQL?

Щоб відповісти на запитання в заголовку: Так , у Postgres 8.4 (випущено 01.07.2009 р. До того, як було задано це питання) або пізнішої версії, ви можете досягти цього, вклавши сукупну функцію у віконну функцію :

SELECT c.yr, count(*) AS ct, max(count(*)) OVER () AS max_ct
FROM   actor   a
JOIN   casting c ON c.actorid = a.id
WHERE  a.name = 'John Travolta'
GROUP  BY c.yr;

Розглянемо послідовність подій у SELECTзапиті:

(Можливий) мінус: функції вікна не агрегують рядки. Ви отримуєте всі рядки, що залишилися після сукупного кроку. Корисно в деяких запитах, але не ідеально для цього.


Щоб отримати один рядок з найбільшим числом, ви можете використовувати ORDER BY ct LIMIT 1як @wolph натякнув :

SELECT c.yr, count(*) AS ct
FROM   actor   a
JOIN   casting c ON c.actorid = a.id
WHERE  a.name = 'John Travolta'
GROUP  BY c.yr
ORDER  BY ct DESC
LIMIT  1;

Використовуючи лише основні функції SQL, доступні в будь-якій пристойній СУБД - LIMITреалізація варіюється:

Або ви можете отримати по одному рядку на групу з найбільшим числом з DISTINCT ON(лише Postgres):


Відповідь

Але ви просили:

... рядки, для яких кількість (*) - макс.

Можливо, більше одного. Найелегантніше рішення - це функція вікнаrank() в підзапиті. Райан надав запит, але він може бути простішим (деталі в моїй відповіді вище):

SELECT yr, ct
FROM  (
   SELECT c.yr, count(*) AS ct, rank() OVER (ORDER BY count(*) DESC) AS rnk
   FROM   actor   a
   JOIN   casting c ON c.actorid = a.id
   WHERE  a.name = 'John Travolta'
   GROUP  BY c.yr
   ) sub
WHERE  rnk = 1;

На сьогодні всі основні СУБД підтримують функції вікна. За винятком MySQL та форків ( MariaDB, схоже, застосував їх нарешті у версії 10.2 ).


[... вам зовсім не потрібно приєднуватися до настільного фільму]. Потрібне приєднання до таблиці "фільм", оскільки це єдина таблиця зі стовпцем "рік" (рік фільму).
Kevin Swann

4

це з цього веб-сайту - http://sqlzoo.net/3.htm 2 можливі рішення:

з ТОП 1 ЗАМОВИТИ ... DESC:

SELECT yr, COUNT(title) 
FROM actor 
JOIN casting ON actor.id=actorid
JOIN movie ON movie.id=movieid
WHERE name = 'John Travolta'
GROUP BY yr
HAVING count(title)=(SELECT TOP 1 COUNT(title) 
FROM casting 
JOIN movie ON movieid=movie.id 
JOIN actor ON actor.id=actorid
WHERE name='John Travolta'
GROUP BY yr
ORDER BY count(title) desc)

з MAX:

SELECT yr, COUNT(title) 
FROM actor  
JOIN casting ON actor.id=actorid    
JOIN movie ON movie.id=movieid
WHERE name = 'John Travolta'
GROUP BY yr
HAVING 
    count(title)=
        (SELECT MAX(A.CNT) 
            FROM (SELECT COUNT(title) AS CNT FROM actor 
                JOIN casting ON actor.id=actorid
                JOIN movie ON movie.id=movieid
                    WHERE name = 'John Travolta'
                    GROUP BY (yr)) AS A)

3

Використання max з обмеженням дасть вам лише перший рядок, але якщо є два або більше рядків з однаковою кількістю максимальної кількості фільмів, ви пропустите деякі дані. Нижче наведено спосіб зробити це, якщо у вас є функція rank () .

SELECT
    total_final.yr,
    total_final.num_movies
    FROM
    ( SELECT 
        total.yr, 
        total.num_movies, 
        RANK() OVER (ORDER BY num_movies desc) rnk
        FROM (
               SELECT 
                      m.yr, 
                      COUNT(*) AS num_movies
               FROM MOVIE m
               JOIN CASTING c ON c.movieid = m.id
               JOIN ACTOR a ON a.id = c.actorid
               WHERE a.name = 'John Travolta'
               GROUP BY m.yr
             ) AS total
    ) AS total_final 
   WHERE rnk = 1

3

Наступний код дає вам відповідь. По суті, він реалізує MAX (COUNT (*)), використовуючи ALL. Вона має ту перевагу, що використовує дуже основні команди та операції.

SELECT yr, COUNT(title)
FROM actor
JOIN casting ON actor.id = casting.actorid
JOIN movie ON casting.movieid = movie.id
WHERE name = 'John Travolta'
GROUP BY yr HAVING COUNT(title) >= ALL
  (SELECT COUNT(title)
   FROM actor
   JOIN casting ON actor.id = casting.actorid
   JOIN movie ON casting.movieid = movie.id
   WHERE name = 'John Travolta'
   GROUP BY yr)

2

Залежно від того, яку базу даних ви використовуєте ...

select yr, count(*) num from ...
order by num desc

Більшість мого досвіду в Sybase, який використовує інший синтаксис, ніж інші БД. Але в цьому випадку ви називаєте свій стовпець підрахунку, щоб ви могли сортувати його за спаданням. Ви можете зробити крок далі і обмежити свої результати першими 10 рядами (щоб знайти його 10 найзайнятіших років).


2

Завдяки останній відповіді

SELECT yr, COUNT(title)
FROM actor
JOIN casting ON actor.id = casting.actorid
JOIN movie ON casting.movieid = movie.id
WHERE name = 'John Travolta'
GROUP BY yr HAVING COUNT(title) >= ALL
  (SELECT COUNT(title)
   FROM actor
   JOIN casting ON actor.id = casting.actorid
   JOIN movie ON casting.movieid = movie.id
   WHERE name = 'John Travolta'
   GROUP BY yr)

У мене була та сама проблема: мені потрібно було знати лише ті записи, кількість яких відповідає максимальному (це може бути один або кілька записів).

Мені потрібно дізнатись більше про "речення ALL", і це саме те просте рішення, яке я шукав.


1
     select top 1 yr,count(*)  from movie
join casting on casting.movieid=movie.id
join actor on casting.actorid = actor.id
where actor.name = 'John Travolta'
group by yr order by 2 desc

1
create view sal as
select yr,count(*) as ct from
(select title,yr from movie m, actor a, casting c
where a.name='JOHN'
and a.id=c.actorid
and c.movieid=m.id)group by yr

----- ПЕРЕГЛЯН СТВОРЕНО -----

select yr from sal
where ct =(select max(ct) from sal)

YR 2013

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.