यहां एक समाधान है जो अधिक सामान्य रूप से काम करता है, भले ही जोड़े एक-दूसरे के ठीक बगल में न हों। (यदि यह वास्तव में आवश्यक है, यदि भागों को जोड़ा नहीं जा सकता है यदि उनकी आईडी लगातार नहीं है, तो उस शर्त को क्वेरी में जोड़ा जा सकता है।)
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
स्पष्टीकरण:आंतरिक क्वेरी में, मैं प्रारंभिक डेटा में दो और कॉलम जोड़ता हूं। एक, rn
, प्रत्येक पहचानकर्ता के लिए 'L' और 'R' के लिए अलग-अलग (1 से शुरू होकर 1 से वृद्धि करके) अलग से गिना जाता है। इसका उपयोग जोड़े बनाने के लिए किया जाएगा। और, ct
प्रत्येक पहचानकर्ता के लिए 'L' और 'R' के लिए कुल संख्याओं में से कम से कम देता है। बाहरी क्वेरी में, मैं केवल उन सभी पंक्तियों को फ़िल्टर करता हूँ जहाँ rn > ct
- वे प्रारंभिक तालिका में एक जोड़ी के बिना पंक्तियाँ हैं। क्या बचा है जोड़े हैं।
जोड़ा गया :अतिरिक्त शर्त के साथ कि एक जोड़ी "लगातार" पंक्तियों से बनाई जानी चाहिए (जैसा कि id
द्वारा मापा जाता है) कॉलम), यह एक और दिलचस्प सवाल बन जाता है। यह एक अंतराल और द्वीप समस्या है (एक ही विशेषता के साथ लगातार पंक्तियों के समूहों की पहचान करें), लेकिन एक मोड़ के साथ:LR
मूल्य स्थिर होने के बजाय समूह के भीतर वैकल्पिक होना चाहिए। बहुत ही कुशल "टैबिबिटोसन" विधि यहां लागू नहीं की जा सकती (मुझे लगता है); "समूह की शुरुआत" विधि, जो अधिक सामान्य है, काम करती है। यही मैंने यहां इस्तेमाल किया है। ध्यान दें कि अंत में मैं एक समूह में अंतिम पंक्ति को छोड़ देता हूं, यदि समूह की संख्या एक विषम संख्या है। (हमें दो, या चार, या छह लगातार पंक्तियाँ मिल सकती हैं जो एक या दो या तीन जोड़े बनाती हैं, लेकिन वैकल्पिक LR के साथ विषम संख्या में पंक्तियाँ नहीं)। यह भी ध्यान दें कि यदि दो पंक्तियों में एक ही पहचानकर्ता और LR है, तो दूसरी पंक्ति हमेशा एक नया समूह शुरू करेगी, इसलिए यदि यह वास्तव में एक जोड़ी का हिस्सा है (इसके बाद की पंक्ति के साथ), तो इस समाधान द्वारा सही ढंग से पकड़ा जाएगा।
इसकी तुलना 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
;