Mysql
 sql >> Baza danych >  >> RDS >> Mysql

SQL:Zwracanie najczęstszej wartości dla każdej osoby

Wstępny komentarz

Naucz się używać wyraźnej notacji JOIN, a nie starej (sprzed 1992 r.) niejawnej notacji dołączania.

Stary styl:

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

Preferowany styl:

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

Potrzebujesz warunku WŁĄCZENIA dla każdego DOŁĄCZENIA.

Ponadto personID wartości w danych to ciągi, a nie liczby, więc musisz pisać

 WHERE personTable.personid = "Ben"

na przykład, aby zapytanie zadziałało na pokazanych tabelach.

Główna odpowiedź

Poszukujesz agregatu agregatu:w tym przypadku maksimum liczebności. Tak więc każde ogólne rozwiązanie będzie obejmować zarówno MAX, jak i COUNT. Nie możesz zastosować MAX bezpośrednio do COUNT, ale możesz zastosować MAX do kolumny z podzapytania, w której kolumną jest COUNT.

Zbuduj zapytanie za pomocą Test-Driven Query Design — TDQD.

Wybierz ocenę osoby i transakcji

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

Wybierz osobę, ocenę i liczbę wystąpień oceny

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

Ten wynik stanie się podzapytanie.

Sprawdź, ile razy dana osoba otrzymuje jakąkolwiek ocenę

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

Teraz wiemy, jaka jest maksymalna liczba dla każdej osoby.

Wymagany wynik

Aby uzyskać wynik, musimy wybrać wiersze z podzapytania, które mają maksymalną liczbę. Pamiętaj, że jeśli ktoś ma 2 dobre i 2 złe oceny (a 2 to maksymalna liczba ocen tego samego typu dla tej osoby), zostaną pokazane dwa rekordy dla tej osoby.

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

Jeśli chcesz również podać rzeczywistą liczbę ocen, możesz to łatwo wybrać.

To dość złożony fragment SQL. Nie chciałbym próbować pisać tego od zera. Rzeczywiście, prawdopodobnie nie zawracałbym sobie głowy; Rozwijałem to krok po kroku, mniej więcej tak, jak pokazano. Ale ponieważ debugowaliśmy podzapytania, zanim użyjemy ich w większych wyrażeniach, możemy być pewni odpowiedzi.

Z klauzulą

Należy zauważyć, że Standard SQL zawiera klauzulę WITH, która poprzedza instrukcję SELECT, nazywając podzapytanie. (Może być również używany do zapytań rekurencyjnych, ale nie potrzebujemy tego tutaj.)

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

To jest prostsze do napisania. Niestety, MySQL nie obsługuje jeszcze klauzuli WITH.

Powyższy kod SQL został przetestowany pod kątem oprogramowania IBM Informix Dynamic Server 11.70.FC2 działającego w systemie Mac OS X 10.7.4. Ten test ujawnił problem zdiagnozowany we wstępnym komentarzu. SQL dla głównej odpowiedzi działał poprawnie bez konieczności zmiany.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL i prawdopodobieństwo zwrócenia złego identyfikatora przez LAST_INSERT_ID()

  2. UPUŚĆ wszystkie klucze obce w bazie danych MYSQL

  3. MySQL — jakiego algorytmu skrótu powinienem do tego użyć?

  4. Przechowuj i iteruj wynik zapytania w mysqli

  5. MySQL vs MongoDB 1000 odczytów