Her er en løsning, der fungerer mere generelt, selvom parrene ikke nødvendigvis findes lige ved siden af hinanden. (Hvis det faktisk er PÅKRÆVET, hvis dele ikke kan parres, hvis deres ID'er ikke er fortløbende, kan denne betingelse føjes til forespørgslen.)
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
;
Output :
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
Forklaring:I den indre forespørgsel tilføjer jeg yderligere to kolonner til de indledende data. En, rn
, tæller separat (startende fra 1 og øges med 1) for hver identifikator, separat for 'L' og for 'R'. Dette vil blive brugt til at danne parrene. Og ct
giver det mindste af det samlede antal for 'L' og 'R' for hver identifikator. I den ydre forespørgsel filtrerer jeg bare alle rækker fra, hvor rn > ct
- det er rækkerne uden et par i den indledende tabel. Hvad der er tilbage er parrene.
TILFØJET :Med den yderligere betingelse, at et par skal dannes ud fra "konsekutive" rækker (som målt ved id
kolonne), bliver dette et mere interessant spørgsmål. Det er et hul-og-ø-problem (identificer grupper af på hinanden følgende rækker med samme karakteristik), men med et twist:LR
værdi skal være vekslende inden for gruppen, snarere end konstant. Den meget effektive "tabibitosan" metode kan ikke anvendes her (tror jeg); metoden "start af gruppe", som er mere generel, virker. Det er hvad jeg brugte her. Bemærk, at jeg i sidste ende udelader den allersidste række i en gruppe, hvis optællingen for gruppen er et ulige tal. (Vi kan finde to, fire eller seks på hinanden følgende rækker, der danner et eller to eller tre par, men ikke et ulige antal rækker med skiftevis LR). Bemærk også, at hvis to rækker har samme identifikator OG LR, vil den anden række altid starte en NY gruppe, så hvis den faktisk er en del af et par (med rækken EFTER det), vil den blive fanget korrekt af denne løsning.
Sammenlign dette med MATCH_RECOGNIZE-løsningen til Oracle 12 og nyere, jeg postede separat - og forstå, hvor meget enklere det er!
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
;