2011-01-23 9 views
8

Ho qualche tipo di richiesta impossibile :).SQL - Dammi 3 hit per ogni tipo solo

Ho una tabella in cui una delle colonne è denominata type. Vorrei selezionare 3 record per ogni tipo in quella colonna. È possibile?

Nota anche che sto usando MySQL e Sphinx.

UPDATE: Struttura della tabella

id  title  type 
1  AAAA   string1 
2  CCCC   string2 
3  EEEE   string2 
4  DDDD   string2 
5  FFFF   string2 
6  BBBB   string2 
6  BBBB   string2 

Quello che voglio la mia MySQL per tornare è (fino a 3 record per ogni tipo ordinato per titolo):

id  title  type 
1  AAAA   string1 
6  BBBB   string2 
2  CCCC   string2 
4  DDDD   string2 
+3

Primo, quasi nulla è impossibile. Secondo, perché non mostrare la struttura della tabella e ciò che hai provato finora. – ircmaxell

risposta

12
select id, title, type 
from (select id, title, type, 
       @num := if(@group = type, @num + 1, 1) as row_number, 
       @group := type as dummy 
     from your_table 
     order by type, title) as x 
where row_number <= 3 

(! Utilizza a different article sullo stesso sito come Martin Wickman's answer)

+0

Molto, molto bello! – xpepermint

+0

+1 per l'ordine fisso di – RichardTheKiwi

0

Partenza this articolo. Dato:

+--------+------------+-------+ 
| type | variety | price | 
+--------+------------+-------+ 
| apple | gala  | 2.79 | 
| apple | fuji  | 0.24 | 
| apple | limbertwig | 2.87 | 
| orange | valencia | 3.59 | 
| orange | navel  | 9.36 | 
| pear | bradford | 6.05 | 
| pear | bartlett | 2.14 | 
| cherry | bing  | 2.55 | 
| cherry | chelan  | 6.33 | 
+--------+------------+-------+ 

Query:

select type, variety, price 
from fruits 
where (
    select count(*) from fruits as f 
    where f.type = fruits.type and f.price < fruits.price 
) <= 2; 
+0

Questa query mostrerà i pareggi, quindi se 4 frutti hanno lo stesso prezzo, tutti mostrano (invece di 3). Non c'è stato anche alcun tentativo di collegare alla domanda. – RichardTheKiwi

+0

Se sei varietà di mele condividessero lo stesso prezzo più basso, tutte e sei sarebbero state restituite. Ma l'esempio dell'OP sto pensando che id sia probabilmente un identificatore univoco (se, cioè, i due "6" sono prodotti come risultato di un JOIN) e potresti usare la colonna id invece della colonna del prezzo per ottenere un risultato corretto garantito. –

2

Quando il tavolo è grande e la raccolta è più imprevedibile, la numerazione fila deve essere ordinato per tipo nella query interna affinché le variabili con effetto collaterale funzionino.

select id, title, type 
from (select id, title, type, 
     @r := CASE WHEN @g = type THEN @r+1 ELSE 1 END r, 
     @g := type 
     from tbl 
     order by type, title) as x 
where row_number <= 3 
# order by type, title 

Un altro modo per fare questo senza usare lato effettuare variabili, se non esistono due record sono esattamente gli stessi su (titolo, tipo, id), è riportata qui sotto. Questo utilizza solo SQL ANSI SQL92 standard. Tuttavia, potrebbe essere più lento di quanto sopra.

select A.id, A.title, A.type 
from tbl A 
left join tbl B on 
    A.title = B.title and 
    (A.type < B.type or 
    (A.type = B.type and A.id < A.id)) 
group by A.id, A.title, A.type 
having count(B.title) <= 2 
+0

Sì, ho notato quello e ho fatto quella correzione prima che questo fosse pubblicato. –

2

Se si dispone di un indice (type, title), e si conoscono i valori possibili per type, credo che SQL dinamico è la strada da percorrere (per una volta) per le migliori prestazioni.

Per ogni valore possibile di type, aggiungere un unione tutti e una selezione per quel tipo specifico. Query finale sarà simile alla seguente query:

(select * from t1 where type = 'string1' order by title limit 3) 
    union all 
(select * from t1 where type = 'string2' order by title limit 3) 
    union all 
(select * from t1 where type = 'string3' order by title limit 3); 

Esegue in meno di 1 secondo su un tavolo con 1.000.000 righe, mentre le altre soluzioni (Martin & Cyberkiwis) richiede circa 11 secondi.

La differenza è perché la query unione sopra può recuperare le prime tre voci di titolo per ciascun tipo e quindi stop, mentre la funzione di analisi simulata deve eseguire la scansione dell'intera tabella.

+0

Il mio database ha 200k record e ci sono più di 500 tipi. Che cosa suggerisci? – xpepermint

+0

@xpepermint, vai con la soluzione Martins. Sappi solo che diventerà più lento man mano che aggiungi i record. A un certo punto, diventerà più veloce per eseguire 500 query in un ciclo. A seconda della configurazione, potrebbe già essere così. Devi misurare te stesso. – Ronnis