Här är en lösning som fungerar mer generellt, även om paren inte nödvändigtvis finns precis bredvid varandra. (Om det i själva verket KRÄVS, om delar inte kan paras om deras ID inte är konsekutiva, kan det villkoret läggas till i frågan.)
with
test_data ( id, lr, identifier ) as (
select '001', 'L', 'B15A' from dual union all
select '002', 'R', 'A15C' from dual union all
select '003', 'L', 'A15C' from dual union all
select '004', 'R', 'A15C' from dual union all
select '005', 'L', 'A15C' from dual union all
select '006', 'R', 'D5A2' from dual union all
select '009', 'R', 'D5A2' from dual union all
select '010', 'L', 'E5A6' from dual union all
select '011', 'R', 'E5A6' from dual union all
select '012', 'L', 'E5A6' from dual union all
select '013', 'R', 'E5A6' from dual union all
select '014', 'R', 'H9S5' from dual union all
select '017', 'L', 'EE5A' from dual union all
select '018', 'R', 'EE5A' from dual
)
-- end of test data, the solution (SQL query) begins below this line
select id, lr, identifier
from ( select id, lr, identifier,
row_number() over (partition by identifier, lr order by id) as rn,
least( count(case when lr = 'L' then 1 end) over (partition by identifier),
count(case when lr = 'R' then 1 end) over (partition by identifier)
) as least_count
from test_data
)
where rn <= least_count
order by id -- ORDER BY is optional
;
Utdata :
ID LR IDENTIFIER
--- -- ----------
002 R A15C
003 L A15C
004 R A15C
005 L A15C
010 L E5A6
011 R E5A6
012 L E5A6
013 R E5A6
017 L EE5A
018 R EE5A
10 rows selected
Förklaring:I den inre frågan lägger jag till ytterligare två kolumner till de initiala uppgifterna. En, rn
, räknas separat (börjar från 1 och ökar med 1) för varje identifierare, separat för "L" och för "R". Detta kommer att användas för att bilda paren. Och, ct
ger det minsta av det totala antalet för 'L' och 'R' för varje identifierare. I den yttre frågan filtrerar jag bara bort alla rader där rn > ct
- det är raderna utan ett par i den initiala tabellen. Det som är kvar är paren.
TILLlagt :Med det ytterligare villkoret att ett par måste bildas från "på varandra följande" rader (mätt med id
kolumn), blir detta en mer intressant fråga. Det är ett problem med luckor och öar (identifiera grupper av på varandra följande rader med samma egenskap), men med en twist:LR
värdet måste vara alternerande inom gruppen snarare än konstant. Den mycket effektiva "tabibitosan"-metoden kan inte tillämpas här (tror jag); metoden "start av grupp", som är mer generell, fungerar. Detta är vad jag använde här. Observera att jag i slutändan utelämnar den allra sista raden i en grupp, om antalet för gruppen är ett udda tal. (Vi kan hitta två, fyra eller sex på varandra följande rader som bildar ett eller två eller tre par, men inte ett udda antal rader med omväxlande LR). Observera också att om två rader har samma identifierare OCH LR kommer den andra raden alltid att starta en NY grupp, så om den faktiskt är en del av ett par (med raden EFTER det), kommer den att fångas korrekt av denna lösning.
Jämför detta med MATCH_RECOGNIZE-lösningen för Oracle 12 och högre som jag postade separat - och uppskatta hur mycket enklare det är!
with
prep ( id, lr, identifier, flag ) as (
select id, lr, identifier,
case when identifier = lag(identifier) over (order by id)
and lr != lag(lr) over (order by id)
then null else 1 end
from test_data -- replace "test_data" with actual table name
),
with_groups ( id, lr, identifier, gp ) as (
select id, lr, identifier,
sum(flag) over (order by id)
from prep
),
with_rn ( id, lr, identifier, rn, ct ) as (
select id, lr, identifier,
row_number() over (partition by identifier, gp order by id),
count(*) over (partition by identifier, gp)
from with_groups
)
select id, lr, identifier
from with_rn
where rn < ct or mod(rn, 2) = 0
order by id -- ORDER BY is optional
;