Inleidende opmerking
Leer de expliciete JOIN-notatie te gebruiken, niet de oude (pre-1992) impliciete join-notatie.
Oude stijl:
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
Voorkeursstijl:
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
Je hebt een AAN-voorwaarde nodig voor elke JOIN.
Ook de personID
waarden in de data zijn strings, geen getallen, dus je zou moeten schrijven
WHERE personTable.personid = "Ben"
bijvoorbeeld om de query te laten werken op de getoonde tabellen.
Hoofdantwoord
U zoekt een aggregaat van een aggregaat:in dit geval het maximum van een telling. Elke algemene oplossing omvat dus zowel MAX als COUNT. U kunt MAX niet rechtstreeks toepassen op COUNT, maar u kunt MAX toepassen op een kolom vanuit een subquery waarbij de kolom toevallig een COUNT is.
Bouw de query op met Test-Driven Query Design — TDQD.
Selecteer persoon en transactiebeoordeling
SELECT p.PersonID, t.Rating, t.TransactionID
FROM PersonTable AS p
JOIN TransactionTable AS t
ON p.TransactionID = t.TransactionID
Selecteer persoon, beoordeling en aantal keren dat de beoordeling voorkomt
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
Dit resultaat wordt een subquery.
Zoek het maximale aantal keren dat de persoon een beoordeling krijgt
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 weten we wat het maximale aantal is voor elke persoon.
Vereist resultaat
Om het resultaat te krijgen, moeten we de rijen uit de subquery selecteren die het maximale aantal hebben. Houd er rekening mee dat als iemand 2 goede en 2 slechte beoordelingen heeft (en 2 het maximale aantal beoordelingen van hetzelfde type voor die persoon is), er twee records voor die persoon worden weergegeven.
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
Als u ook het werkelijke aantal beoordelingen wilt, is dat eenvoudig te selecteren.
Dat is een vrij complex stukje SQL. Ik zou het vreselijk vinden om te proberen dat helemaal opnieuw te schrijven. Inderdaad, ik zou waarschijnlijk niet de moeite nemen; Ik zou het stap voor stap ontwikkelen, min of meer zoals weergegeven. Maar omdat we de subquery's hebben opgespoord voordat we ze in grotere uitdrukkingen gebruiken, kunnen we zeker zijn van het antwoord.
WITH clausule
Houd er rekening mee dat Standard SQL een WITH-component bevat die voorafgaat aan een SELECT-instructie en een subquery noemt. (Het kan ook worden gebruikt voor recursieve zoekopdrachten, maar dat hebben we hier niet nodig.)
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
Dit is eenvoudiger te schrijven. Helaas ondersteunt MySQL de WITH-clausule nog niet.
De bovenstaande SQL is nu getest tegen IBM Informix Dynamic Server 11.70.FC2 die draait op Mac OS X 10.7.4. Die test bracht het probleem aan het licht dat in de inleidende opmerking werd vastgesteld. De SQL voor het hoofdantwoord werkte correct zonder te hoeven worden gewijzigd.