2009-07-07 5 views
2

Meine Daten sieht wie folgt aus:Wie Sie die neuesten 2 Artikel pro Kategorie in einem wählen bekommen (mit mysql)

 
id|category|insertdate|title.... 
-------------------------------- 
1|1|123|test 1 
2|1|124|test 2 
3|1|125|test 3 
4|2|102|test 4 
5|2|103|test 5 
6|2|104|test 6 

Was ich versuche, die spätestens 2 Einträge pro Kategorie zu erreichen, wird zu erhalten (wie in Ordnung von Insert DESC), so sollte das Ergebnis sein:

 
id|.... 
---- 
3|.... 
2|.... 
6|.... 
5|.... 

Erste die spätestens mit group by ist einfach, aber wie bekomme ich die neuesten 2 ohne mehrere Abfragen zu starten?

Danke für jede Hilfe ;-)
S.

Antwort

3

Hier gehts Kumpel!

SET @counter = 0; 
SET @category = ''; 

SELECT 
    * 
FROM 
(
    SELECT 
     @counter := IF(data.category = @category, @counter+1, 0) AS counter, 
     @category := data.category, 
     data.* 
    FROM 
    (
     SELECT 
      * 
     FROM test 
     ORDER BY category, date DESC 
    ) data 
) data 
HAVING counter < 2 
+0

Das sollte ein WHERE Zähler <2 anstelle von HAVING sein, aber abgesehen davon ist es eine ideale Antwort, wenn potenziell ineffizient, da es durch jeden Datensatz gehen muss. – Welbog

+0

Ich habe versucht, das HAVING im zweiten Subselect zu haben, aber Counter "war zu diesem Zeitpunkt noch nicht gesetzt" oder "der Optimierer hat das vor dem @counter ausgeführt" ... daher wird natürlich auch ein WHERE die Arbeit im Outer erledigen ein. –

0

Sie werden in der Lage sein, diese Art von Abfrage in einer SELECT-Anweisung nicht, aber man kann es in einer Stored Procedure einpacken, die zurückgibt ein Datensatz, indem Ergebnisse einer Unterabfrage zu einer temporären Tabelle für jede Kategorie hinzugefügt werden und der Inhalt der temporären Tabelle zurückgegeben wird.

Pseudocode:

Create a temp table 
For each distinct category, 
    Add the last two records to the temp table 
Return the temp table 

Sie werden mit dem Satz von Daten landen Sie am Ende wollen, und aus der Sicht der Anwendung nur eine Abfrage gemacht wurde.

0

Eine andere Möglichkeit wäre, eine geordnete Liste mit group_concat zu erhalten. Dies würde jedoch nichts nützen, wenn Sie viele Daten hätten.

select group_concat(id order by insertdate desc separator ','), category from tablename group by category 

oder mit Unter wählt (dies auf mysql)

select category, 
    (select id from test as test1 where test1.category = test.category order by insertdate desc limit 0,1) as recent1, 
    (select id from test as test1 where test1.category = test.category order by insertdate desc limit 1,1) as recent2 
from test 
group by category; 

weiß, dass ich die zweite Option nicht technisch ein wählen ist, da es Sub-Abfragen aber es ist der einzige Weg, ich sehe zu tun es.

7

Dies ist ein schwieriges Problem in SQL, die durch beste beantwortet wird Sie zu ein ausgezeichneten in ausführlichen Artikeln Richten die Ausgabe abdeckt: How to select the first/least/max row per group in SQL. Es umfasst MySQL-spezifische Mittel, um dies zu tun, sowie generische Methoden.

+3

Ausgezeichnete Ressource! Eine viel umfassendere Antwort mit klareren Details in. –

0
SELECT * 
FROM category AS c1 
WHERE (
    SELECT COUNT(c2.id) 
    FROM category AS c2 
    WHERE c2.id = c1.id AND c2.insertdate > c1.insertdate 
) < 2 
Verwandte Themen