sql >> Database teknologi >  >> RDS >> Mysql

SQL:Returnerer den mest almindelige værdi for hver person

Foreløbig kommentar

Lær at bruge den eksplicitte JOIN-notation, ikke den gamle (før 1992) implicitte join-notation.

Gammel 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

Foretrukken 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

Du skal have en TIL-tilstand for hver JOIN.

Også personID værdier i dataene er strenge, ikke tal, så du skal skrive

 WHERE personTable.personid = "Ben"

for eksempel for at få forespørgslen til at virke på de viste tabeller.

Hovedsvar

Du søger at finde et aggregat af et aggregat:i dette tilfælde maksimum af en tælling. Så enhver generel løsning vil involvere både MAX og COUNT. Du kan ikke anvende MAX direkte på COUNT, men du kan anvende MAX på en kolonne fra en underforespørgsel, hvor kolonnen tilfældigvis er et COUNT.

Byg forespørgslen op ved hjælp af testdrevet forespørgselsdesign — TDQD.

Vælg person og transaktionsvurdering

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

Vælg person, bedømmelse og antal forekomster af bedømmelse

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

Dette resultat bliver en underforespørgsel.

Find det maksimale antal gange, personen får en vurdering

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

Nu ved vi, hvad der er det maksimale antal for hver person.

Påkrævet resultat

For at få resultatet skal vi vælge de rækker fra underforespørgslen, som har det maksimale antal. Bemærk, at hvis nogen har 2 gode og 2 dårlige vurderinger (og 2 er det maksimale antal vurderinger af samme type for den pågældende person), så vil der blive vist to poster for den pågældende person.

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

Hvis du også vil have det faktiske bedømmelsestal, er det nemt at vælge.

Det er et ret komplekst stykke SQL. Jeg ville nødig prøve at skrive det fra bunden. Faktisk ville jeg nok ikke gide; Jeg ville udvikle det trin for trin, mere eller mindre som vist. Men fordi vi har fejlrettet underforespørgslerne, før vi bruger dem i større udtryk, kan vi være sikre på svaret.

WITH klausul

Bemærk, at Standard SQL giver et WITH-udtryk, der præfikser en SELECT-sætning, der navngiver en underforespørgsel. (Det kan også bruges til rekursive forespørgsler, men det har vi ikke brug for her.)

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

Dette er nemmere at skrive. Desværre understøtter MySQL endnu ikke WITH-klausulen.

Ovenstående SQL er nu testet mod IBM Informix Dynamic Server 11.70.FC2, der kører på Mac OS X 10.7.4. Den test afslørede det problem, der blev diagnosticeret i den foreløbige kommentar. SQL'en for hovedsvaret fungerede korrekt uden at skulle ændres.



  1. Bootstrapping SQL Express fra WiX?

  2. Postgresql opretter ikke db med "createdb" som superbruger, men udsender ikke fejl

  3. Forskellen mellem In memory-databaser og diskhukommelsesdatabase

  4. Hvordan kan jeg få enum mulige værdier i en MySQL-database?