sql >> Databáze >  >> RDS >> Mysql

SQL:Vrací nejběžnější hodnotu pro každou osobu

Předběžný komentář

Naučte se prosím používat explicitní zápis JOIN, nikoli starý (před rokem 1992) implicitní zápis spojení.

Starý 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

Preferovaný 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

Pro každý JOIN potřebujete podmínku ON.

Také personID hodnoty v datech jsou řetězce, nikoli čísla, takže budete muset napsat

 WHERE personTable.personid = "Ben"

například, aby dotaz fungoval na zobrazených tabulkách.

Hlavní odpověď

Snažíte se najít souhrn souhrnu:v tomto případě maximum počtu. Jakékoli obecné řešení tedy bude zahrnovat MAX i COUNT. MAX nelze použít přímo na COUNT, ale můžete použít MAX na sloupec z dílčího dotazu, kde je sloupec náhodou COUNT.

Sestavte dotaz pomocí Test-Driven Query Design — TDQD.

Vyberte osobu a hodnocení transakce

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

Vyberte osobu, hodnocení a počet výskytů hodnocení

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

Tento výsledek se stane dílčím dotazem.

Najděte maximální počet, kolikrát daná osoba získala jakékoli hodnocení

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

Nyní víme, jaký je maximální počet pro každou osobu.

Požadovaný výsledek

Abychom získali výsledek, musíme z dílčího dotazu vybrat řádky, které mají maximální počet. Všimněte si, že pokud má někdo 2 dobrá a 2 špatná hodnocení (a 2 je maximální počet hodnocení stejného typu pro tuto osobu), zobrazí se pro tuto osobu dva záznamy.

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

Pokud chcete také skutečný počet hodnocení, můžete to snadno vybrat.

To je poměrně složitá část SQL. Nerad bych to zkusil napsat od začátku. Pravděpodobně bych se tím neobtěžoval; Vyvíjel bych to krok za krokem, víceméně tak, jak je ukázáno. Ale protože jsme odladili dílčí dotazy, než je použijeme ve větších výrazech, můžeme si být jisti odpovědí.

S klauzulí

Všimněte si, že standardní SQL poskytuje klauzuli WITH, která předznamenává příkaz SELECT a pojmenovává dílčí dotaz. (Lze jej také použít pro rekurzivní dotazy, ale to zde nepotřebujeme.)

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

Tohle je jednodušší napsat. MySQL bohužel zatím nepodporuje klauzuli WITH.

Výše uvedený SQL byl nyní testován proti IBM Informix Dynamic Server 11.70.FC2 běžícím na Mac OS X 10.7.4. Tento test odhalil problém diagnostikovaný v předběžném komentáři. SQL pro hlavní odpověď fungovalo správně, aniž by bylo nutné je měnit.



  1. Postgresql -bash:psql:příkaz nenalezen

  2. Úplný seznam znakových sad podporovaných MariaDB

  3. Spojte dva sloupce a přidejte je do jednoho nového sloupce

  4. EM SQL Monitor dopad