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

MySQL unterstützt die Limit-Klausel in einem Subselect nicht, wie kann ich das tun?

SELECT ... LIMIT wird in Unterabfragen nicht unterstützt, fürchte ich, also ist es an der Zeit, die Selbstverknüpfungsmagie auszubrechen:

SELECT article.*
FROM article
JOIN (
    SELECT a0.category_id AS id, MIN(a2.article_id) AS lim
    FROM article AS a0
    LEFT JOIN article AS a1 ON a1.category_id=a0.category_id AND a1.article_id>a0.article_id
    LEFT JOIN article AS a2 ON a2.category_id=a1.category_id AND a2.article_id>a1.article_id
    GROUP BY id
) AS cat ON cat.id=article.category_id
WHERE article.article_id<=cat.lim OR cat.lim IS NULL
ORDER BY article_id;

Das Bit in der Mitte ermittelt die ID des Artikels mit der drittniedrigsten ID für jede Kategorie, indem versucht wird, drei Kopien derselben Tabelle in aufsteigender ID-Reihenfolge zu verknüpfen. Wenn es weniger als drei Artikel für eine Kategorie gibt, stellen die Left Joins sicher, dass das Limit NULL ist, also muss das äußere WHERE diesen Fall ebenfalls aufnehmen.

Wenn sich Ihre „Top 3“-Anforderung irgendwann in „Top n“ ändern könnte, wird dies unhandlich. In diesem Fall sollten Sie die Idee überdenken, zuerst die Liste der unterschiedlichen Kategorien abzufragen und dann die Abfragen pro Kategorie zu vereinen.

ETA:Bestellung auf zwei Spalten:eek, neue Anforderungen! :-)

Es kommt darauf an, was Sie meinen:Wenn Sie nur versuchen, die Endergebnisse zu bestellen, können Sie es ohne Probleme am Ende schlagen. Aber wenn Sie diese Reihenfolge verwenden müssen, um auszuwählen, welche drei Artikel kommissioniert werden sollen, ist die Sache viel schwieriger.

Wir verwenden einen Self-Join mit „<“, um den Effekt zu reproduzieren, den „ORDER BY article_id“ hätte. Leider können Sie zwar „ORDER BY a, b“, aber nicht do '(a, b)<(c, d)'... Du kannst auch nicht 'MIN(a, b)' machen. Außerdem würden Sie eigentlich nach drei Spalten sortieren, issticky, released und article_id, da Sie sicherstellen müssen, dass jeder Bestellwert eindeutig ist, um zu vermeiden, dass vier oder mehr Zeilen zurückgegeben werden.

Während Sie könnten Erstellen Sie Ihren eigenen bestellbaren Wert durch eine grobe Ganzzahl- oder Zeichenfolgenkombination von Spalten:

LEFT JOIN article AS a1
ON a1.category_id=a0.category_id
AND HEX(a1.issticky)+HEX(a1.published_at)+HEX(a1.article_id)>HEX(a0.issticky)+HEX(a0.published_at)+HEX(a0.article_id)

dies wird undurchführbar hässlich, und die Berechnungen werden jede Möglichkeit zunichte machen, die Indizes zu verwenden, um die Abfrage effizient zu machen. An diesem Punkt sind Sie besser dran, einfach die separaten LIMITed-Abfragen pro Kategorie durchzuführen.