Mysql
 sql >> Datenbank >  >> RDS >> Mysql

SQL:Rückgabe des häufigsten Werts für jede Person

Vorbemerkung

Bitte lernen Sie, die explizite JOIN-Notation zu verwenden, nicht die alte (vor 1992) implizite Join-Notation.

Alter Stil:

SELECT transactionTable.rating as MostCommonRating 
FROM personTable, transactionTable 
WHERE personTable.transactionid = transactionTable.transactionid 
AND personTable.personid = 1
GROUP BY transactionTable.rating 
ORDER BY COUNT(transactionTable.rating) desc 
LIMIT 1

Bevorzugter Stil:

SELECT transactionTable.rating AS MostCommonRating 
  FROM personTable
  JOIN transactionTable 
    ON personTable.transactionid = transactionTable.transactionid 
 WHERE personTable.personid = 1
 GROUP BY transactionTable.rating 
 ORDER BY COUNT(transactionTable.rating) desc 
 LIMIT 1

Sie benötigen für jeden JOIN eine ON-Bedingung.

Auch die personID Werte in den Daten sind Strings, keine Zahlen, also müssten Sie schreiben

 WHERE personTable.personid = "Ben"

zum Beispiel, damit die Abfrage mit den angezeigten Tabellen funktioniert.

Hauptantwort

Sie suchen ein Aggregat eines Aggregats:in diesem Fall das Maximum einer Anzahl. Jede allgemeine Lösung wird also sowohl MAX als auch COUNT beinhalten. Sie können MAX nicht direkt auf COUNT anwenden, aber Sie können MAX auf eine Spalte aus einer Unterabfrage anwenden, wo die Spalte zufällig ein COUNT ist.

Erstellen Sie die Abfrage mithilfe von Test-Driven Query Design – TDQD.

Personen- und Transaktionsbewertung auswählen

SELECT p.PersonID, t.Rating, t.TransactionID
  FROM PersonTable AS p
  JOIN TransactionTable AS t
    ON p.TransactionID = t.TransactionID

Person, Bewertung und Häufigkeit der Bewertung auswählen

SELECT p.PersonID, t.Rating, COUNT(*) AS RatingCount
  FROM PersonTable AS p
  JOIN TransactionTable AS t
    ON p.TransactionID = t.TransactionID
 GROUP BY p.PersonID, t.Rating

Dieses Ergebnis wird zu einer Unterabfrage.

Finden Sie heraus, wie oft die Person maximal bewertet wird

SELECT s.PersonID, MAX(s.RatingCount)
  FROM (SELECT p.PersonID, t.Rating, COUNT(*) AS RatingCount
          FROM PersonTable AS p
          JOIN TransactionTable AS t
            ON p.TransactionID = t.TransactionID
         GROUP BY p.PersonID, t.Rating
       ) AS s
 GROUP BY s.PersonID

Jetzt wissen wir, was die maximale Anzahl für jede Person ist.

Erforderliches Ergebnis

Um das Ergebnis zu erhalten, müssen wir die Zeilen aus der Unterabfrage auswählen, die die maximale Anzahl haben. Beachten Sie, dass, wenn jemand 2 gute und 2 schlechte Bewertungen hat (und 2 die maximale Anzahl von Bewertungen desselben Typs für diese Person ist), zwei Datensätze für diese Person angezeigt werden.

SELECT s.PersonID, s.Rating
  FROM (SELECT p.PersonID, t.Rating, COUNT(*) AS RatingCount
          FROM PersonTable AS p
          JOIN TransactionTable AS t
            ON p.TransactionID = t.TransactionID
         GROUP BY p.PersonID, t.Rating
       ) AS s
  JOIN (SELECT s.PersonID, MAX(s.RatingCount) AS MaxRatingCount
          FROM (SELECT p.PersonID, t.Rating, COUNT(*) AS RatingCount
                  FROM PersonTable AS p
                  JOIN TransactionTable AS t
                    ON p.TransactionID = t.TransactionID
                 GROUP BY p.PersonID, t.Rating
               ) AS s
         GROUP BY s.PersonID
       ) AS m
    ON s.PersonID = m.PersonID AND s.RatingCount = m.MaxRatingCount

Wenn Sie auch die tatsächliche Bewertungsanzahl wünschen, können Sie diese ganz einfach auswählen.

Das ist ein ziemlich komplexes Stück SQL. Ich würde es hassen, zu versuchen, das von Grund auf neu zu schreiben. Tatsächlich würde ich wahrscheinlich nicht die Mühe machen; Ich würde es Schritt für Schritt entwickeln, mehr oder weniger wie gezeigt. Da wir die Unterabfragen jedoch debuggt haben, bevor wir sie in größeren Ausdrücken verwenden, können wir uns auf die Antwort verlassen.

WITH-Klausel

Beachten Sie, dass Standard-SQL eine WITH-Klausel bereitstellt, die einer SELECT-Anweisung vorangestellt ist und eine Unterabfrage benennt. (Es kann auch für rekursive Abfragen verwendet werden, aber das brauchen wir hier nicht.)

WITH RatingList AS
     (SELECT p.PersonID, t.Rating, COUNT(*) AS RatingCount
        FROM PersonTable AS p
        JOIN TransactionTable AS t
          ON p.TransactionID = t.TransactionID
       GROUP BY p.PersonID, t.Rating
     )
SELECT s.PersonID, s.Rating
  FROM RatingList AS s
  JOIN (SELECT s.PersonID, MAX(s.RatingCount) AS MaxRatingCount
          FROM RatingList AS s
         GROUP BY s.PersonID
       ) AS m
    ON s.PersonID = m.PersonID AND s.RatingCount = m.MaxRatingCount

Das ist einfacher zu schreiben. Leider unterstützt MySQL die WITH-Klausel noch nicht.

Die obige SQL wurde nun mit IBM Informix Dynamic Server 11.70.FC2 getestet, das auf Mac OS X 10.7.4 ausgeführt wird. Dieser Test deckte das in der Vorbemerkung diagnostizierte Problem auf. Das SQL für die Hauptantwort funktionierte korrekt, ohne dass Änderungen vorgenommen werden mussten.