sql >> Base de Datos >  >> RDS >> Mysql

SQL:devolviendo el valor más común para cada persona

Comentario preliminar

Aprenda a usar la notación JOIN explícita, no la antigua (anterior a 1992) notación implícita de unión.

Estilo antiguo:

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

Estilo preferido:

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

Necesita una condición ON para cada JOIN.

Además, el personID los valores en los datos son cadenas, no números, por lo que debe escribir

 WHERE personTable.personid = "Ben"

por ejemplo, para que la consulta funcione en las tablas que se muestran.

Respuesta principal

Está buscando encontrar un agregado de un agregado:en este caso, el máximo de un conteo. Entonces, cualquier solución general involucrará tanto MAX como COUNT. No puede aplicar MAX directamente a COUNT, pero puede aplicar MAX a una columna de una subconsulta donde la columna resulta ser COUNT.

Cree la consulta utilizando el Diseño de consulta basado en pruebas:TDQD.

Seleccione la calificación de la persona y la transacción

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

Seleccione persona, calificación y número de ocurrencias de calificación

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

Este resultado se convertirá en una subconsulta.

Encuentre el número máximo de veces que la persona obtiene una calificación

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

Ahora sabemos cuál es el conteo máximo para cada persona.

Resultado requerido

Para obtener el resultado, debemos seleccionar las filas de la subconsulta que tienen el recuento máximo. Tenga en cuenta que si alguien tiene 2 calificaciones buenas y 2 malas (y 2 es el número máximo de calificaciones del mismo tipo para esa persona), se mostrarán dos registros para esa persona.

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

Si también desea contar la calificación real, puede seleccionarla fácilmente.

Esa es una pieza bastante compleja de SQL. Odiaría intentar escribir eso desde cero. De hecho, probablemente no me molestaría; Lo desarrollaría paso a paso, más o menos como se muestra. Pero debido a que hemos depurado las subconsultas antes de usarlas en expresiones más grandes, podemos estar seguros de la respuesta.

Cláusula CON

Tenga en cuenta que Standard SQL proporciona una cláusula WITH que precede a una declaración SELECT, nombrando una subconsulta. (También se puede usar para consultas recursivas, pero no lo necesitamos aquí).

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

Esto es más simple de escribir. Desafortunadamente, MySQL aún no es compatible con la cláusula WITH.

El SQL anterior ahora se ha probado con IBM Informix Dynamic Server 11.70.FC2 ejecutándose en Mac OS X 10.7.4. Esa prueba expuso el problema diagnosticado en el comentario preliminar. El SQL para la respuesta principal funcionó correctamente sin necesidad de cambiarlo.