sql >> Database >  >> RDS >> Mysql

MySQL ondersteunt de limit-clausule in een subselect niet, hoe kan ik dat doen?

SELECTEER ... LIMIT wordt niet ondersteund in subquery's, vrees ik, dus het is tijd om de magie van self-join te doorbreken:

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;

De bit in het midden berekent de ID van het op twee na laagste ID-artikel voor elke categorie door te proberen drie exemplaren van dezelfde tabel samen te voegen in oplopende ID-volgorde. Als er minder dan drie artikelen voor een categorie zijn, zorgen de linker joins ervoor dat de limiet NULL is, dus de buitenste WHERE moet dat geval ook oppikken.

Als uw "top 3"-vereiste op een bepaald moment zou kunnen veranderen in "top n", begint dit onpraktisch te worden. In dat geval wilt u misschien het idee heroverwegen om eerst de lijst met afzonderlijke categorieën te doorzoeken en vervolgens de zoekopdrachten per categorie samen te voegen.

ETA:Bestellen op twee kolommen:eek, nieuwe eisen! :-)

Het hangt ervan af wat je bedoelt:als je alleen de uiteindelijke resultaten probeert te bestellen, kun je het op het einde knallen, geen probleem. Maar als je deze volgorde moet gebruiken om te selecteren welke drie artikelen moeten worden gepickt, is het een stuk moeilijker.

We gebruiken een self-join met '<' om het effect te reproduceren dat 'ORDER BY article_id' zou hebben. Helaas, terwijl je 'ORDER BY a, b' kunt doen, kun je niet doe ‘(a, b)<(c, d)’... evenmin kun je ‘MIN(a, b)’ doen. Bovendien zou je eigenlijk sorteren op drie kolommen, issticky, gepubliceerd en article_id, omdat u ervoor moet zorgen dat elke bestelwaarde uniek is, om te voorkomen dat er vier of meer rijen worden geretourneerd.

Terwijl je kon verzin uw eigen bestelwaarde met een ruwe integer of stringcombinatie van kolommen:

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)

dit wordt onhaalbaar lelijk, en de berekeningen zullen elke kans om de indices te gebruiken om de zoekopdracht efficiënt te maken tenietdoen. Op dat moment kunt u beter gewoon de afzonderlijke BEPERKTE zoekopdrachten per categorie uitvoeren.



  1. SQLite - ORDER OP RAND()

  2. Vereist om deel te nemen aan 2 tafels met hun FK's in een 3e tafel

  3. Fatale fout:aanroep naar ongedefinieerde methode mysqli_stmt::get_result()

  4. ORA-00001 unieke beperking geschonden