2013-04-09 7 views
5

Zum Beispiel habe ich die folgende Tabelle:Was ist der beste Weg, um die ersten beiden Datensätze jeder Gruppe mit einem "SELECT" -Befehl auszuwählen?

id group data 
1 1 aaa 
2 1 aaa 
3 2 aaa 
4 2 aaa 
5 2 aaa 
6 3 aaa 
7 3 aaa 
8 3 aaa 

Was ist der beste Weg, um die ersten beiden Datensätze jeder Gruppe durch einen „SELECT“ Befehl auswählen? Wenn es keine gute Möglichkeit, dies zu tun, was Routine schlagen Sie vor? (In PHP)

(Modellergebnis)

1 1 aaa 
2 1 aaa 
3 2 aaa 
4 2 aaa 
6 3 aaa 
7 3 aaa 

Ich wusste, dass Cross-Beitritt von a.id> = b. ID in einer Sub-Abfrage kann funktionieren, aber ich suche nach einer besser skalierbaren Lösung, die auf eine Tabelle mit Millionen von Datensätzen angewendet werden kann. Dank

+0

Was RDBMS verwenden? MySQL, SQL Server, ...? –

+0

Ihre Select-Abfrage mit LIMIT 2 am Ende, wenn Sie nur zwei Datensätze möchten –

+0

vorzugsweise MySQL, aber ich bin eher gerne die Möglichkeit, zu wissen, so einfach zu verwenden, die Sie vertraut sind. –

Antwort

8
select a.* 
from Tablename a 
where 
(
    select count(*) 
    from Tablename as b 
    where a.group = b.group and a.id >= b.id 
) <= 2 
+0

Das ist eine Lösung, die von meinem Freund vorgeschlagen wurde, indem ich 'a.id <= b.id' für Cross-Joining verwendete, aber ich sah ein großes Leistungsproblem, dass der unbestimmte Abschnitt von 'count (*)' in der Index-Power anwächst Der Tisch wird groß. Habe ich recht? Ich weiß, dass mein Ausdruck ein wenig verwirrend sein kann. –

+0

es funktioniert gut, aber es gibt nicht die ersten zwei Datensätze, gibt es die letzten zwei Datensätze, so überprüfen Sie es besser .. –

+1

@Deepanshu kann es einfach in 'a.id> = b.id' hier ändern http: //www.sqlfiddle.com/#!2/1b596/3 –

-1

Sie wählen, Filter und Ihre Abfrage wie normale bestellen und dann

für MSSQL

SELECT TOP 2 * FROM foo; 

Von dem, was ich Sybase, Oracle und möglich ein paar andere erinnern kann RDBMS verwendet diese Syntax zu.

für MySQL Sie tun

SELECT * FROM foo LIMIT 2; 

Update:

Ja, ich Ihre Frage falsch verstanden, sorry. Scheint wie ein paar von uns haben :)

Dann hängt es davon ab, ob Sie RDBMS unterstützt MIT oder nicht etc. Sie eine Abfrage konstruieren könnte mit MIT oder mit IN und eine Unterabfrage in der IN Klausel.

Für MSSQL denke ich, Sie so etwas wie (Code nicht getestet) tun könnte

SELECT id, data 
    FROM (
     SELECT id, data, Rank() over (Partition BY group ORDER BY id DESC) AS Rank 
     FROM table 
     ) rs WHERE Rank <= 2) 

Aber da diese auf Ihrem RDBMS hängt Ich bitte Sie, bei ähnlichen Fragen suchen und sehen, welche am besten funktioniert, für Ihren Fall seit MSSQL unterstützt einige Dinge MySQL nicht und umgekehrt.

Hier sind einige Beispiele

Select top 10 records for each category

How to select the last two records for each topic_id in MySQL

+0

Sie haben die Frage wahrscheinlich falsch gelesen. Für diesen Fall benötige ich 2 Datensätze pro Gruppe. –

3

ich diesen Trick gefallen, das macht den Einsatz von GROUP_CONCAT Aggregatfunktion und FIND_IN_SET:

SELECT 
    Tablename.* 
FROM 
    Tablename INNER JOIN (
    SELECT `group`, GROUP_CONCAT(id ORDER BY id) ids 
    FROM Tablename 
    GROUP BY `group`) grp ON 
    Tablename.`group` = grp.`group` AND 
    FIND_IN_SET(Tablename.id, ids)<=2 
ORDER BY 
    Tablename.`group`, Tablename.id 

Performance nicht zu gut sein können, da es nicht die Verwendung eines Index machen.

Oder Sie können auch verwenden:

SELECT t1.id, t1.`group`, t1.data 
from 
    Tablename t1 INNER JOIN Tablename t2 
    ON t1.`group` = t2.`group` AND t1.id>=t2.id 
GROUP BY 
    t1.id, t1.`group`, t1.data 
HAVING 
    COUNT(*)<=2 
ORDER BY 
    t1.`group`, t1.id, t1.data 
+0

upvoted für alternativen Vorschlag –