Berikut adalah solusi yang bekerja lebih umum, bahkan jika pasangan tidak selalu ditemukan tepat di sebelah satu sama lain. (Jika itu memang DIBUTUHKAN, jika bagian tidak dapat dipasangkan jika ID mereka tidak berurutan, kondisi itu dapat ditambahkan ke kueri.)
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
;
Keluaran :
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
Penjelasan:Dalam kueri dalam, saya menambahkan dua kolom lagi ke data awal. Satu, rn
, menghitung secara terpisah (mulai dari 1 dan bertambah dengan 1) untuk setiap pengenal, secara terpisah untuk 'L' dan untuk 'R'. Ini akan digunakan untuk membentuk pasangan. Dan, ct
memberikan paling sedikit jumlah total untuk 'L' dan 'R' untuk setiap pengenal. Di kueri luar, saya hanya memfilter semua baris di mana rn > ct
- itu adalah baris tanpa pasangan di tabel awal. Yang tersisa adalah pasangan.
DITAMBAHKAN :Dengan syarat tambahan bahwa pasangan harus dibentuk dari baris "berturut-turut" (diukur dengan id
kolom), ini menjadi pertanyaan yang lebih menarik. Ini adalah masalah gaps-and-islands (identifikasi grup baris berurutan dengan karakteristik yang sama), tetapi dengan twist:LR
nilai harus bergantian dalam kelompok, bukan konstan. Metode "tabibitosan" yang sangat efisien tidak dapat diterapkan di sini (saya pikir); metode "mulai dari grup", yang lebih umum, berhasil. Inilah yang saya gunakan di sini. Perhatikan bahwa pada akhirnya saya meninggalkan baris terakhir dalam sebuah grup, jika hitungan untuk grup adalah angka ganjil. (Kita mungkin menemukan dua, atau empat, atau enam baris berurutan yang membentuk satu atau dua atau tiga pasang, tetapi bukan jumlah baris ganjil dengan LR bergantian). Perhatikan juga bahwa jika dua baris memiliki pengenal AND LR yang sama, baris kedua akan selalu memulai grup BARU, jadi jika itu sebenarnya bagian dari pasangan (dengan baris SETELAHnya), itu akan ditangkap dengan benar oleh solusi ini.
Bandingkan ini dengan solusi MATCH_RECOGNIZE untuk Oracle 12 dan di atasnya yang saya posting secara terpisah - dan hargai betapa lebih sederhananya!
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
;