SELECCIONE LÍMITE 1 por valor de columna?

10

Digamos que tengo la siguiente tabla

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 2         | awesome       |
| 3         | i hate this   |
| 3         | okay          |
| 6         | this is weird |
| 6         | hello?        |
| 6         | what is it    |
| 9         | how are you   |
| 16        | too slow      |
| 16        | yes           |
| 17        | alrighty      |
-----------------------------

¿Cómo puede seleccionar una fila por user_id? Entonces mis resultados serían:

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 3         | i hate this   |
| 6         | this is weird |
| 9         | how are you   |
| 16        | too slow      |
| 17        | alrighty      |
-----------------------------

¿Es esto posible con una sola consulta eficiente? ¿O son sub-seleccionados necesarios? ¿Es posible usar de alguna manera DISTINCTen una sola columna?

Jake Wilson
fuente

Respuestas:

9

Para eso GROUP BYse usa. Obtenga una fila (por grupo). En este caso, se mostrará todos los distintos user_idvalores y para el resto de las columnas, se puede (que) usar las funciones de agregado como MIN(), MAX(), AVG(), SUM()ya que tendrá más de un valor por grupo y sólo uno puede ser mostrado.

SELECT
    user_id
  , MIN(comment) AS comment  -- it will show the first in alphabetical order  
                             -- you could also use MAX()
FROM
    tableX
GROUP BY
    user_id ;

MySQL también permite la siguiente solución poco ortodoxa, que devolverá un comentario (más o menos aleatorio) por usuario:

SELECT
    user_id
  , comment
FROM
    tableX
GROUP BY
    user_id ;

Esta última consulta no funcionará, pero generará un error si el modo (más estricto) ONLY_FULL_GROUP_BYestá habilitado. En la versión 5.7 recientemente lanzada, este modo es el predeterminado y se proporciona una nueva función ANY_VALUE(). Para obtener más detalles, consulte la página de Manejo de MySQLGROUP BY . La consulta se puede escribir ahora:

SELECT
    user_id
  , ANY_VALUE(comment) AS comment
FROM
    tableX
GROUP BY
    user_id ;

Tenga en cuenta que con la versión "poco ortodoxa" o con la ANY_VALUE()función reciente , si agregamos más columnas en la SELECTlista, no se garantiza que sus valores sean de la misma fila, solo de una fila del mismo grupo. La forma en que se seleccionan no es exactamente aleatoria, depende del plan de ejecución y de los índices utilizados.

ypercubeᵀᴹ
fuente
¿Hay alguna otra forma de especificar qué fila se extrae para un user_id? ¿Alguna forma de especificar un tipo de ORDER BY?
Jake Wilson el
Además MINy MAX?
ypercubeᵀᴹ
1
Entonces es más complejo. Vea esta otra pregunta: MySQL Query - ¿Cómo obtener la demografía más reciente?
ypercubeᵀᴹ
2
También encontrará una tonelada de problemas similares en el sitio SO, debajo de la [greatest-n-per-group]etiqueta.
ypercubeᵀᴹ
1
@ T.BrianJones, ¿quiere decir en la consulta "poco ortodoxa", si agrega todas las demás columnas en la lista SELECCIONAR? Es el primero, puede que no sean de la misma fila. No es exactamente al azar, pero los valores pueden ser de diferentes filas (del mismo grupo).
ypercubeᵀᴹ