2013-04-09 10 views
5

Per esempio io ho la seguente tabella:Qual è il modo migliore per selezionare i primi due record di ogni gruppo con un comando "SELECT"?

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 

Qual è il modo migliore per selezionare i primi due dischi di ogni gruppo da un comando "SELECT"? Se non c'è buon modo per farlo, cosa di routine cosa suggerisce? (In PHP)

(esito modello)

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

sapevo che trasversale che unisce da a.id> = b. l'ID in una sottoquery può funzionare ma sto cercando una soluzione più scalabile che possa essere applicata su una tabella con milioni di record. Grazie

+0

Cosa RDBMS che si sta utilizzando? MySQL, SQL Server, ... ?? –

+0

vostra query di selezione con LIMIT 2 alla fine, se si desidera solo due record –

+0

preferibilmente di MySQL, ma io sono un po 'come conoscere il possibile modo per farlo, quindi è sufficiente utilizzare quello che si ha familiarità con. –

risposta

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

Questa è una soluzione suggerita dal mio amico usando 'a.id <= b.id' per l'unione incrociata, ma ho previsto un grosso problema di prestazioni che la sezione indeterminata di' count (*) 'sta crescendo nel potere dell'indice quando il tavolo sta crescendo. Ho ragione? So che la mia espressione potrebbe essere un po 'confusa però. –

+0

Si sta lavorando bene, ma non dare i primi due dischi, che sta dando ultimi due dischi, quindi meglio controllare .. –

+1

@Deepanshu può essere semplicemente cambiare in 'a.id> = b.id' qui http: //www.sqlfiddle.com/#!2/1b596/3 –

-1

Si seleziona, filtrare e ordinare la query come normale e poi

per MSSQL

SELECT TOP 2 * FROM foo; 

Da quello che posso ricordare Sybase, Oracle ed eventuale pochi altri L'RDBMS utilizza questa sintassi per.

per MySQL fate

SELECT * FROM foo LIMIT 2; 

Aggiornamento:

Sì, ho letto male la tua domanda, mi spiace. Sembra che alcuni di noi hanno fatto :)

Poi dipende dal fatto che si RDBMS supportaAVENTI o no ecc Si potrebbe costruire una query utilizzando AVENTI o utilizzando IN e una sottoquery nella NELLA clausola.

Per MSSQL Penso che si potrebbe fare qualcosa di simile (codice non testato)

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

Ma poiché questo dipende dalla vostra RDBMS vi chiedo di guardare domande simili e vedere quale funziona meglio per il tuo caso dal MSSQL supporta alcune cose MySQL no e viceversa.

Ecco alcuni esempi

Select top 10 records for each category

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

+0

Probabilmente hai letto male la domanda. Per quell'istanza, avrò bisogno di 2 record per gruppo. –

3

Mi piace questo trucco, che fa uso di funzione di aggregazione group_concat e 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 

Spettacoli non può essere troppo buono, in quanto non può fare uso di un indice.

Oppure si può anche usare questo:

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 per suggerimento alternativo –

Problemi correlati