2012-04-17 13 views
7

Ho due tabelle: tableA (idA, titleA) e tableB (idB, idA, textB) con una relazione uno a molti tra di loro. Per ogni riga nella tabellaA, voglio recuperare le ultime 5 righe corrispondenti nella tabellaB (ordinate da idB).Ottieni il primo/ultimo n record per gruppo di

Ho provato

SELECT * FROM tableA INNER JOIN tableB ON tableA.idA = tableB.idA LIMIT 5 

ma è solo limitando il risultato globale di INNER JOIN mentre io voglio limitare il risultato per ogni diversa tableA.id

Come posso fare questo?

Grazie

+0

Per l'ultimo 5 per ... C'è una base per l'ultimo 5 nella tabella B, o solo l'ultimo 5 basato su "idB" che sembrerebbe essere una colonna di sequenza di incremento automatico. Se basato sulla data, quale colonna sarebbe ... – DRapp

+0

Si basa su idB, che è autoincrementato. –

+0

Domande simili: http://stackoverflow.com/questions/4688664/mysql-select-n-records-base-on-group-by e http://stackoverflow.com/questions/5319643/top-n-per- group-with-multiple-table-joins e forse http://stackoverflow.com/q/7539548 - un'estensione di [this] (http://stackoverflow.com/q/8748986) e [this] (http://stackoverflow.com/q/1313120) – TMS

risposta

2

Penso che questo sia quello che vi serve:

SELECT tableA.idA, tableA.titleA, temp.idB, temp.textB 
FROM tableA 
INNER JOIN 
(
    SELECT tB1.idB, tB2.idA, 
    (
     SELECT textB 
     FROM tableB 
     WHERE tableB.idB = tB1.idB 
    ) as textB 
    FROM tableB as tB1 
     JOIN tableB as tB2 
      ON tB1.idA = tB2.idA AND tB1.idB >= tB2.idB 
    GROUP BY tB1.idA, tB1.idB 
    HAVING COUNT(*) <= 5 
    ORDER BY idA, idB 
) as temp 
ON tableA.idA = temp.idA 

Maggiori informazioni su questo metodo qui:

http://www.sql-ex.ru/help/select16.php

+1

Perché hai la terza selezione annidata ('seleziona il testoB dalla tabellaB dove tableB.idB = tB1.idB') ?? Questa sottoquery può essere sostituita solo con 'tB1.textB'! – TMS

+0

e sostituisci 'inner join' con' join'.Non renderlo un mistero più grande di quello che è :-) – TMS

+2

@ user1336526, ho semplificato e corretto questa soluzione di Carlos, vedere la mia risposta. – TMS

0

Garantire tabella "B" ha un indice su (IDA, idB) per ordine ottimizzato da scopi quindi per ogni "A" ID, può avere rapidamente l'ordine "B" scendendo così mettendo il più recente verso l'alto PER CIASCUN ID "A". Usando le variabili MySQL, ogni volta che l'ID "A" cambia, ripristina il rank su 1 per il successivo ID "A".

select 
     B.idA, 
     B.idB, 
     B.textB 
     @RankSeq := if(@LastAGroup = B.idA, @RankSeq +1, 1) ARankSeq, 
     @LastAGroup := B.idA as ignoreIt 
    from 
     tableB B 
     JOIN tableA A 
      on B.idA = A.idA, 
     (select @RankSeq := 0, @LastAGroup := 0) SQLVars 
    having 
     ARankSeq <= 5 
    order by 
     B.idA, 
     B.idB DESC 
+0

Ugh! Nasty query :-) Guarda [molto più semplice variante] (http://stackoverflow.com/a/4688699/684229). In ogni caso c'è un grande svantaggio nelle prestazioni - MySQL deve percorrere tutte le righe. – TMS

0
select * from tablea ta, tableb tb 
where ta.ida=tb.idb and tb.idb in 
(select top 5 idb from tableB order by idb asc/desc) 
  • (crescente se si desidera ids inferiori desc se si desidera un numero maggiore di ID)
  • meno complicato e facile da includere più condizioni
  • se superiore clausola non è presente nella clausola limite uso mysql (non ho molta conoscenza circa mysql)
+0

Sta chiedendo i primi 5 nella tabellaB per ogni riga nella tabellaA. Ciò limita la tabellaB alle sue prime 5 righe, ordinate da idb. Inoltre è necessario utilizzare LIMIT per MySQL, non TOP. – Aaron

+0

grazie per i vostri commenti mi rendo conto del mio errore ...... funzionerà ... selezionare * da tablea ta, tableb tb dove ta.ida = tb.idb e tb.idb in (selezionare idb dalla tabellaB, tableA tableB.idb = tableA.ida order by idb asc/desc limit 5) .. –

5

Molto soluzione semplificata e corretto Carlos (il suo soluzione sarebbe tornare prime 5 file, non ultimo ...):

SELECT tB1.idA, tB1.idB, tB1.textB 
FROM tableB as tB1 
    JOIN tableB as tB2 
     ON tB1.idA = tB2.idA AND tB1.idB <= tB2.idB 
GROUP BY tB1.idA, tB1.idB 
HAVING COUNT(*) <= 5 

in MySQL, è possibile utilizzare tB1.textB anche se è query GROUP bY, perché si sta raggruppamento per la BIS nella prima tabella, quindi non c'è è solo un valore singolo di tB1.textB per ciascuno gruppo ...

+0

Solo una nota, solo per non dimenticarlo: è ancora dubbio quale soluzione potrebbe migliorare - la soluzione di unione è in linea di principio quadratica, mentre la la soluzione di rango è lineare. Detto questo, è abbastanza probabile che l'ottimizzatore SQL ridurrà il problema quadratico a quello lineare, mentre non ci si possono aspettare ulteriori ottimizzazioni dalla soluzione di classificazione. Lo stesso vale per le soluzioni di [questa domanda simile] (http://stackoverflow.com/q/8748986). – TMS

+0

La mia esperienza generale in MySQL è, se riesci a riscrivere la query sottoquery/classifica per partecipare, sarà più veloce .. – TMS

Problemi correlati