Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie wählt man die neuesten vier Artikel pro Kategorie aus?

Dies ist das Größt-n-pro-Gruppen-Problem und eine sehr häufige SQL-Frage.

So löse ich es mit äußeren Verknüpfungen:

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;

Ich nehme den Primärschlüssel des item an Tabelle ist item_id , und dass es sich um einen monoton steigenden Pseudoschlüssel handelt. Das heißt, ein größerer Wert in item_id entspricht einer neueren Zeile in item .

So funktioniert es:Für jeden Artikel gibt es einige andere Artikel, die neuer sind. Beispielsweise sind drei Elemente neuer als das viertneueste Element. Es gibt null Artikel, die neuer sind als der allerneueste Artikel. Wir wollen also jedes Element vergleichen (i1 ) zum Satz von Elementen (i2 ), die neuer sind und dieselbe Kategorie wie i1 haben . Wenn die Anzahl dieser neueren Elemente weniger als vier beträgt, i1 ist einer von denen, die wir einschließen. Fügen Sie es andernfalls nicht hinzu.

Das Schöne an dieser Lösung ist, dass sie unabhängig davon funktioniert, wie viele Kategorien Sie haben, und weiterhin funktioniert, wenn Sie die Kategorien ändern. Es funktioniert auch, wenn die Anzahl der Elemente in einigen Kategorien weniger als vier beträgt.

Eine andere Lösung, die funktioniert, aber auf die MySQL-Benutzervariablenfunktion angewiesen ist:

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 hat die Unterstützung für SQL-Standardfensterfunktionen eingeführt. Jetzt können wir diese Art von Problem so lösen, wie es andere RDBMS tun:

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;