2012-04-17 17 views
7

Mam dwie tabele: tableA (idA, titleA) i tableB (idB, idA, textB) z jednym do wielu relacji między nimi. Dla każdego wiersza w tabeli A chcę pobrać ostatnie 5 wierszy odpowiadających w tabeli B (uporządkowanej przez idB).Zdobądź pierwsze/ostatnie n rekordów na grupę przez

Próbowałem

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

ale to ograniczenie globalnego wynik INNER JOIN natomiast chcę ograniczyć wynik dla każdej innej tableA.id

W jaki sposób można to zrobić?

Dzięki

+0

Za ostatnie 5 za ... Czy istnieje podstawa dla ostatnich 5 w tabeli B lub tylko ostatnich 5 w oparciu o "idB", który wydaje się być kolumną sekwencji automatycznej inkrementacji. Jeśli w oparciu o datę, jaka kolumna by to była ... – DRapp

+0

Jest oparta na idB, która jest automatycznie zwiększana. –

+0

Podobne pytania: http://stackoverflow.com/questions/4688664/mysql-select-n-records-base-on-group-by i http://stackoverflow.com/questions/5319643/top-n-per- group-with-multiple-table-joins i może http://stackoverflow.com/q/7539548 - rozszerzenie [this] (http://stackoverflow.com/q/8748986) i [this] (http://stackoverflow.com/q/1313120) – TMS

Odpowiedz

2

myślę, że to jest to, czego potrzebujesz:

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 

Więcej informacji na temat tej metody tutaj:

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

+1

Dlaczego masz trzeci zagnieżdżony wybór ('wybierz tekstB z tabeliB, gdzie tableB.idB = tB1.idB')? Podzapytanie to można zastąpić tylko 'tB1.textB'! – TMS

+0

i zamień 'join wewnętrzny' na' join'.Nie róbcie z tego większej tajemnicy niż to :-) – TMS

+2

@ user1336526, Uproszyłem i poprawiłem to rozwiązanie Carlosa, zobacz moją odpowiedź. – TMS

0

Upewnij się, że tabela „B” ma indeks (IDA, IDB) dla optymalnej kolejności przez celów więc dla każdego „A” ID, może szybko mieć „B” malejącej więc kładzenie Najnowszy na górze PER EACH "A" ID. Przy użyciu zmiennych MySQL za każdym razem, gdy zmienia się identyfikator "A", resetuje on pozycję z powrotem do 1 dla następnego identyfikatora "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! Paskudne zapytanie :-) Spójrz na [znacznie prostszy wariant] (http://stackoverflow.com/a/4688699/684229). W każdym razie istnieje duża wada wydajności - MySQL musi przechodzić przez wszystkie wiersze. – 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) 
  • (ASC jeśli chcą niższych IDS desc, jeśli chcesz wyższego identyfikatora)
  • mniej skomplikowane i łatwo zawierać więcej warunków
  • jeśli top klauzula nie występuje w klauzuli ograniczyć korzystanie MySQL (nie mam dużo wiedzy abt mysql)
+0

Poprosił o 5 najlepszych w tabeli B dla każdego wiersza w tabeliA. Ogranicza to tylko tableB do 5 najlepszych wierszy, uporządkowanych według idb. Musisz również użyć LIMIT dla MySQL, a nie TOP. – Aaron

+0

dziękuję za komentarze i zdaję sobie sprawę z mojego błędu ...... czy to zadziała .... wybierz * z tablea ta, tableb tb gdzie ta.ida = tb.idb i tb.idb w (wybierz idb z tableB, tableA tableB.idb = tableA.AIDA order by idb asc/desc limit 5) .. –

5

bardzo uproszczone i poprawione rozwiązanie Carlos (His rozwiązaniem byłoby powrócić pierwsze 5 wierszy, nie ostatni ...):

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 

w MySQL, można użyć tB1.textB nawet jeśli jest to grupa o zapytania, ponieważ jesteś grupowanie przez IDB w pierwszej tabeli, więc nie jest tylko jedną wartością: tB1.textB dla każdego grupa ...

+0

Po prostu zapamiętaj, żeby o tym nie zapomnieć: wciąż pozostaje pytanie, które rozwiązanie lepiej się sprawdzi - rozwiązanie łączące jest w zasadzie kwadratowe, a rozwiązanie rangowe jest liniowe. To powiedziawszy, jest całkiem prawdopodobne, że optymalizator SQL sprawi, że problem z kwadratem spadnie do liniowego, podczas gdy nie można oczekiwać więcej optymalizacji od rozwiązania rankingowego. To samo dotyczy rozwiązań [tego podobnego pytania] (http://stackoverflow.com/q/8748986). – TMS

+0

Moje ogólne doświadczenie w MySQL polega na tym, że jeśli możesz przepisać kwerendę podkwerendy/rankingu, aby dołączyć, będzie to szybsze. – TMS

Powiązane problemy