Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment SÉLECTIONNER les quatre articles les plus récents par catégorie ?

C'est le problème du plus grand n par groupe, et c'est une question SQL très courante.

Voici comment je le résous avec des jointures externes :

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;

Je suppose la clé primaire de l'item la table est item_id , et qu'il s'agit d'une pseudo-clé à croissance monotone. Autrement dit, une valeur supérieure dans item_id correspond à une ligne plus récente dans item .

Voici comment cela fonctionne :pour chaque élément, il existe un certain nombre d'autres éléments qui sont plus récents. Par exemple, il y a trois éléments plus récents que le quatrième élément le plus récent. Il n'y a aucun élément plus récent que l'élément le plus récent. Nous voulons donc comparer chaque élément (i1 ) à l'ensemble des éléments (i2 ) qui sont plus récents et ont la même catégorie que i1 . Si le nombre de ces nouveaux éléments est inférieur à quatre, i1 est l'un de ceux que nous incluons. Sinon, ne l'incluez pas.

La beauté de cette solution est qu'elle fonctionne quel que soit le nombre de catégories que vous avez et continue de fonctionner si vous modifiez les catégories. Cela fonctionne également même si le nombre d'éléments dans certaines catégories est inférieur à quatre.

Une autre solution qui fonctionne mais s'appuie sur la fonctionnalité des variables utilisateur 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 a introduit la prise en charge des fonctions de fenêtre standard SQL. Nous pouvons maintenant résoudre ce type de problème comme le font les autres SGBDR :

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;