これは、ペアが必ずしも隣り合っていない場合でも、より一般的に機能するソリューションです。 (それが実際に必要な場合、IDが連続していないためにパーツをペアリングできない場合は、その条件をクエリに追加できます。)
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
;
出力 :
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
説明:内部クエリで、初期データにさらに2つの列を追加します。 1つ、rn
、「L」と「R」で別々に、識別子ごとに別々にカウントします(1から始まり1ずつ増加します)。これは、ペアを形成するために使用されます。そして、ct
各識別子の「L」と「R」の合計カウントの最小値を示します。外側のクエリでは、rn > ct
であるすべての行を除外するだけです。 -これらは、初期テーブルにペアがない行です。残っているのはペアです。
追加 :「連続した」行からペアを形成する必要があるという追加の条件があります(id
で測定)。 列)、これはより興味深い質問になります。これはギャップと島の問題です(同じ特性を持つ連続する行のグループを識別します)が、ひねりがあります:LR
値は、一定ではなく、グループ内で交互になっている必要があります。非常に効率的な「タビビトサン」法はここでは適用できません(私は思います)。より一般的な「グループの開始」メソッドは機能します。これは私がここで使用したものです。グループのカウントが奇数の場合、最終的にグループの最後の行を省略していることに注意してください。 (1つまたは2つまたは3つのペアを形成する2つ、4つ、または6つの連続した行が見つかる場合がありますが、LRが交互になっている奇数の行は見つかりません)。また、2つの行が同じ識別子AND LRを持っている場合、2番目の行は常に新しいグループを開始するため、実際にペアの一部である場合(その後の行と)、このソリューションによって正しくキャッチされることにも注意してください。
これを、個別に投稿したOracle 12以降のMATCH_RECOGNIZEソリューションと比較してください。そして、それがどれほど単純であるかを理解してください。
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
;