Aqui está uma solução que funciona de forma mais geral, mesmo que os pares não sejam necessariamente encontrados um ao lado do outro. (Se isso for de fato NECESSÁRIO, se as partes não puderem ser emparelhadas se seus IDs não forem consecutivos, essa condição pode ser adicionada à consulta.)
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
;
Saída :
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
Explicação:Na consulta interna, adiciono mais duas colunas aos dados iniciais. Um,
rn
, conta separadamente (começando em 1 e incrementando em 1) para cada identificador, separadamente para 'L' e para 'R'. Isso será usado para formar os pares. E, ct
dá a menor das contagens totais para 'L' e 'R' para cada identificador. Na consulta externa, apenas filtro todas as linhas em que rn > ct
- essas são as linhas sem par na tabela inicial. O que resta são os pares. ADICIONADO :Com a condição adicional de que um par deve ser formado a partir de linhas "consecutivas" (conforme medido pelo
id
coluna), esta se torna uma questão mais interessante. É um problema de lacunas e ilhas (identifique grupos de linhas consecutivas com a mesma característica), mas com uma diferença:o LR
valor deve ser alternado dentro do grupo, em vez de constante. O método "tabibitosan" muito eficiente não pode ser aplicado aqui (eu acho); o método "início do grupo", que é mais geral, funciona. Isso é o que eu usei aqui. Observe que, no final, deixo de fora a última linha de um grupo, se a contagem do grupo for um número ímpar. (Podemos encontrar duas, quatro ou seis fileiras consecutivas que formam um ou dois ou três pares, mas não um número ímpar de fileiras com LR alternado). Observe também que se duas linhas tiverem o mesmo identificador AND LR, a segunda linha sempre iniciará um NOVO grupo, portanto, se de fato fizer parte de um par (com a linha APÓS ela), isso será capturado corretamente por esta solução. Compare isso com a solução MATCH_RECOGNIZE para Oracle 12 e superior que postei separadamente - e aprecie o quanto é mais simples!
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
;