Kann ich in SQL ein Maximum (count (*)) machen?

75

Hier ist mein Code:

    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

Hier ist die Frage

Welches waren die geschäftigsten Jahre für 'John Travolta'. Zeigen Sie die Anzahl der Filme, die er für jedes Jahr gemacht hat.

Hier ist die Tabellenstruktur:

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

Dies ist die Ausgabe, die ich bekomme:

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

Ich muss die Zeilen bekommen, für die count(*)max.

Wie mache ich das?

Alex Gordon
quelle
1
In der Frage werden RDBMS und Version nicht offengelegt. Die Antwort hängt sehr davon ab.
Erwin Brandstetter
Die intelligenteste (und wahrscheinlich schnellste Antwort ohne Unterabfrage ) ist hier : Verwenden Sie LIMIT 1diese Option, um die Unterabfrage zu vermeiden.
Kaiser

Antworten:

95

Verwenden:

  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

Wenn Sie nach num_movies DESCbestellen, werden die höchsten Werte oben in der Ergebnismenge angezeigt. Wenn mehrere Jahre die gleiche Anzahl haben, m.yrwird das letzte Jahr an die Spitze gesetzt ... bis sich der nächste num_moviesWert ändert.

Kann ich einen MAX (COUNT (*)) verwenden?


Nein, Sie können Aggregatfunktionen in derselben SELECT-Klausel nicht übereinander legen. Das innere Aggregat müsste in einer Unterabfrage ausgeführt werden. IE:

SELECT MAX(y.num)
  FROM (SELECT COUNT(*) AS num
          FROM TABLE x) y
OMG Ponys
quelle
3
Ja, Sie können MAX (COUNT (*)) verwenden, aber in Oracle. techonthenet.com/sql/max.php
Andrejs
1
@OMG Ponys - Diese Antwort war WIRKLICH ausgezeichnet - Das erste von Ihnen bereitgestellte SQL funktioniert (obvs), ABER das zweite von Ihnen bereitgestellte SQL ist so elegant UND hat es mir ermöglicht, auch die Unterabfrage besser zu verstehen! DANKE, dass Sie sich die Mühe gemacht haben, eine vollständig erweiterte Antwort zu geben. Ich habe versucht, dies zu erreichen - aber auch mit einer Gruppe von - und dies hat es durchaus möglich gemacht!
Kiltannen
1
Nur um dies besser zu verstehen - Wie würden Sie diese zweite Abfrage verwenden, um das Jahr mit der maximalen Anzahl von Filmen zu erhalten? So wie es jetzt ist, kann es identifizieren, wie viele Filme in dem Jahr passiert sind, in dem die meisten Filme gedreht wurden - aber es wird nicht angegeben, welches Jahr das war. Ich würde gerne verstehen, wie man einen zweiten Wert aus der Unterabfrage zurückgibt, bei der es sich um den Group By-Wert handelt, der mit dem MAX-Ergebnis korreliert
kiltannen
28

Bestellen count(*) descSie einfach vorbei und Sie erhalten das Höchste (wenn Sie es mit kombinieren limit 1)

Wolph
quelle
7
Was wäre, wenn ich mehrere Zeilen mit dem Maximalwert hätte und alle Werte anzeigen möchte, die einen "Maximalwert" haben
Adam
@WhyCry: Nicht ganz sicher, was Sie versuchen, dies zu fragen, aber wenn Sie die Antwort auf Stackoverflow nicht finden können, sollten Sie es einfach als separate Frage stellen :)
Wolph
@Wolph sagt, dass Sie mehrere Zeilen mit dem gleichen Maximalwert haben können, mit Limit 1 können Sie das nicht sehen
urSus
Nach dem erneuten Lesen dieses (3 Jahre alten) Kommentars denke ich, dass er suchtHAVING MAX(...) = ...
Wolph
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
Kraft
quelle
ORDER BY ohne LIMIT / TOP in einer Unterabfrage hat keine Auswirkung.
Philipxy
5

Diese Frage ist alt, wurde aber in einer neuen Frage auf dba.SE referenziert . Ich bin der Meinung, dass die besten Lösungen noch nicht bereitgestellt wurden, daher füge ich eine weitere hinzu.

Zunächst einmal, referentielle Integrität angenommen ( in der Regel mit Fremdschlüssel - Constraints erzwungen) Sie nicht auf den Tisch kommen müssen überhaupt . Das ist tote Fracht in Ihrer Anfrage. Alle bisherigen Antworten weisen nicht darauf hin.movie


Kann ich eine max(count(*))in SQL machen?

So beantworten Sie die Frage im Titel: Ja , in Postgres 8.4 (veröffentlicht am 01.07.2009, bevor diese Frage gestellt wurde) oder später können Sie dies erreichen, indem Sie eine Aggregatfunktion in eine Fensterfunktion verschachteln :

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;

Betrachten Sie die Reihenfolge der Ereignisse in einer SELECTAbfrage:

Die (möglichen) Nachteile: Fensterfunktionen aggregieren keine Zeilen. Sie erhalten alle Zeilen nach dem Aggregatschritt übrig. Nützlich bei einigen Abfragen, aber nicht ideal für diese.


Um eine Zeile mit der höchsten Zählung, können Sie ORDER BY ct LIMIT 1wie @wolph angedeutet :

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;

Verwenden Sie nur grundlegende SQL-Funktionen, die in einem halbwegs anständigen RDBMS verfügbar sind. Die LIMITImplementierung variiert:

Oder Sie erhalten eine Zeile pro Gruppe mit der höchsten Anzahl mit DISTINCT ON(nur Postgres):


Antworten

Aber Sie haben gefragt:

... Zeilen, für die count (*) max.

Möglicherweise mehr als eine. Die eleganteste Lösung ist die Fensterfunktionrank() in einer Unterabfrage. Ryan hat eine Anfrage gestellt , die aber einfacher sein kann (Details in meiner Antwort oben):

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;

Alle wichtigen RDBMS-Unterstützungsfensterfunktionen werden heutzutage verwendet. Außer MySQL und Forks ( MariaDB scheint sie endlich in Version 10.2 implementiert zu haben ).

Erwin Brandstetter
quelle
[... Sie müssen sich überhaupt nicht dem Tischfilm anschließen]. Eine Verknüpfung mit der Tabelle 'Film' ist erforderlich, da dies die einzige Tabelle mit der Spalte 'Jahr' (Jahr des Films) ist.
Kevin Swann
4

es ist von dieser Seite - http://sqlzoo.net/3.htm 2 mögliche Lösungen:

mit TOP 1 eine BESTELLUNG NACH ... 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)

mit 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)
Ropman
quelle
3

Wenn Sie max mit einem Limit verwenden, erhalten Sie nur die erste Zeile. Wenn jedoch zwei oder mehr Zeilen mit der gleichen Anzahl maximaler Filme vorhanden sind, werden einige Daten fehlen. Im Folgenden finden Sie eine Möglichkeit, dies zu tun, wenn Sie die Funktion rank () zur Verfügung haben.

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
Ryan Goltry
quelle
3

Der folgende Code gibt Ihnen die Antwort. Es implementiert im Wesentlichen MAX (COUNT (*)) unter Verwendung von ALL. Es hat den Vorteil, dass es sehr grundlegende Befehle und Operationen verwendet.

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)
user765195
quelle
2

Abhängig davon, welche Datenbank Sie verwenden ...

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

Der größte Teil meiner Erfahrung liegt in Sybase, das eine andere Syntax als andere DBs verwendet. In diesem Fall benennen Sie Ihre Zählspalte, damit Sie sie in absteigender Reihenfolge sortieren können. Sie können noch einen Schritt weiter gehen und Ihre Ergebnisse auf die ersten 10 Zeilen beschränken (um seine 10 geschäftigsten Jahre zu finden).

Tim
quelle
2

Danke an die letzte Antwort

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)

Ich hatte das gleiche Problem: Ich musste nur die Datensätze kennen, deren Anzahl mit der maximalen Anzahl übereinstimmt (es können ein oder mehrere Datensätze sein).

Ich muss mehr über die "ALL-Klausel" lernen, und genau diese einfache Lösung habe ich gesucht.

Andres
quelle
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
Eugene
quelle
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

----- ERSTELLTE ANSICHT -----

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

JAHR 2013

Saksham Varshney
quelle