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

¿Cómo SELECCIONAR los cuatro artículos más nuevos por categoría?

Este es el mayor problema de n por grupo, y es una pregunta de SQL muy común.

Así es como lo resuelvo con combinaciones externas:

SELECT i1.*
FROM item i1
LEFT OUTER JOIN item i2
  ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id)
GROUP BY i1.item_id
HAVING COUNT(*) < 4
ORDER BY category_id, date_listed;

Estoy asumiendo la clave principal del item la tabla es item_id , y que es una pseudoclave que aumenta monótonamente. Es decir, un valor mayor en item_id corresponde a una fila más nueva en item .

Así es como funciona:para cada elemento, hay una cantidad de otros elementos que son más nuevos. Por ejemplo, hay tres elementos más nuevos que el cuarto elemento más nuevo. No hay artículos más nuevos que el artículo más nuevo. Así que queremos comparar cada elemento (i1 ) al conjunto de elementos (i2 ) que son más nuevos y tienen la misma categoría que i1 . Si el número de esos elementos más nuevos es inferior a cuatro, i1 es uno de los que incluimos. De lo contrario, no lo incluyas.

La belleza de esta solución es que funciona sin importar cuántas categorías tenga y continúa funcionando si cambia las categorías. También funciona incluso si la cantidad de elementos en algunas categorías es inferior a cuatro.

Otra solución que funciona pero se basa en la función de variables de usuario de MySQL:

SELECT *
FROM (
    SELECT i.*, @r := IF(@g = category_id, @r+1, 1) AS rownum, @g := category_id
    FROM (@g:=null, @r:=0) AS _init
    CROSS JOIN item i
    ORDER BY i.category_id, i.date_listed
) AS t
WHERE t.rownum <= 3;

MySQL 8.0.3 introdujo soporte para funciones de ventana estándar de SQL. Ahora podemos resolver este tipo de problema de la misma manera que lo hacen otros RDBMS:

WITH numbered_item AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY item_id) AS rownum
  FROM item
)
SELECT * FROM numbered_item WHERE rownum <= 4;