Temat: SQL - zwracanie dwóch pierwszych rekordów
W pierwszej kolejności to zastanowiłbym się co kryje się pod pojęciem 'pierwsze dwa rekordy' ?
Z zapytania
select owner, action
from t1, t2
where id = t1_id and owner = "JA";
wynika, że rekordy zostaną zwrócone tak jak zechce engine bazy. Proponowałbym przesortować po polu 'action', żeby mieć ogólne pojęcie o tym które rekordy zostaną zrzucone (no chyba, że to nie jest istotne).
Z zapytania przykładowego wynika również, że stosujesz je tyle razy ile masz id do sprawdzenia. Jak chcesz ograniczyć to użyj klauzuli limit
select
owner,
action
from t1, t2
where id = t1_id and owner = "JA"
limit 2;
Otrzymasz wtedy dla jednego id dokładnie dwa rekordy w wyniku.
Na końcu pytasz jak wyświetlić dla wszystkich id po dwa rekordy co kompletnie zmienia podejście do tematu.
Przygotowuję sobie zestaw danych do testowania
drop table if exists t2;
drop table if exists t1;
create table t1(
ID int primary key,
OWNER varchar(500)
)
engine = innodb
default character set = utf8;
create table t2(
t1_id int,
ACTION varchar(500),
constraint t1_fkey foreign key (t1_id)
references t1 (ID) match simple
on update no action on delete cascade
)
engine = innodb
default character set = utf8;
insert into t1 values ( 1, 'A' );
insert into t1 values ( 2, 'B' );
insert into t1 values ( 3, 'C' );
insert into t2 values ( 1, 'Akcja 1' );
insert into t2 values ( 1, 'Akcja 2' );
insert into t2 values ( 1, 'Akcja 3' );
insert into t2 values ( 2, 'Akcja 1' );
insert into t2 values ( 3, 'Akcja 1' );
insert into t2 values ( 3, 'Akcja 2' );
a następnie sporządzam zapytanie SQL
set @oid = -9999;
set @count = 1;
select
dane.*
from (
select
result.*,
@count := if ( @oid = result.ID, @count + 1, 1 ) as lp,
@oid := result.ID
from (
select
t1.ID,
t1.OWNER,
t2.action
from t1
join t2 on t1.ID = t2.t1_id
order by id
) as result
) as dane
where dane.lp < 3;
Zapytanie zwraca dane dla wszystkich id ograniczając jednocześnie liczbę zwracanych rekordów z tabeli t2 do 2.
Tworzę dwie zmienne: @oid która przechowuje id z poprzedniego rekordu (na starcie dziwna wartość bo od czegoś trzeba zacząć. Musi to być liczba inna od najniższego id w tabeli t1) oraz licznik @count który będzie zliczał wiersze danego id.
1. Wyszukuję id, owner, action z tabel (najgłębsze podzapytanie; alias result) pamiętając o tym, że wynik musi być posortowany po id (bo dane w tabelach mogą leżeć różnie a fakt, że chcemy zliczać wiersz po wierszu wymusza uporządkowaną strukturę na której będziemy pracowali)
2. Wyświetlam jeszcze raz dane z 'result' (w podzapytaniu alias dane) i dołączam do nich lp czyli wynik zmiennej count powiększony o 1 ale tyko wtedy kiedy bieżący oraz poprzedni rekord są takie same. Jeżeli są różne to ustawiam licznik na 1 i taką wartość wpisuje do lp. Po wykonaniu operacji wpisania liczby do kolumny lp przypisuje id z bieżącego rekordu do zmiennej @oid
3. Na samym końcu ograniczam zwracany wynik do lp < 3 czyli wyświetlam tylko dwa rekordy (gdzie lp = 1 lub lp = 2
Jeżeli masz listę id które potrzebujesz zwrócić dodaj na końcu w where kod:
and dane.id in ('JA', 'TY', 'ONI')