Hier ist eine Lösung, die allgemeiner funktioniert, auch wenn die Paare nicht unbedingt direkt nebeneinander liegen. (Falls dies tatsächlich ERFORDERLICH ist, wenn Teile nicht gepaart werden können, wenn ihre IDs nicht aufeinander folgen, kann diese Bedingung zur Abfrage hinzugefügt werden.)
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
;
Ausgabe :
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
Erläuterung:In der inneren Abfrage füge ich den Anfangsdaten zwei weitere Spalten hinzu. Eins, rn
, zählt separat (von 1 beginnend und um 1 aufsteigend) für jeden Bezeichner, separat für 'L' und für 'R'. Dies wird verwendet, um die Paare zu bilden. Und ct
gibt die kleinste der Gesamtzahlen für 'L' und 'R' für jeden Bezeichner an. In der äußeren Abfrage filtere ich einfach alle Zeilen heraus, in denen rn > ct
ist - das sind die Zeilen ohne Paar in der Anfangstabelle. Was übrig bleibt, sind die Paare.
Hinzugefügt :Mit der zusätzlichen Bedingung, dass aus "aufeinanderfolgenden" Zeilen (gemessen an der id
) ein Paar gebildet werden muss Spalte), wird dies eine interessantere Frage. Es ist ein Lücken-und-Inseln-Problem (identifiziere Gruppen aufeinanderfolgender Zeilen mit demselben Merkmal), aber mit einer Wendung:dem LR
Der Wert muss innerhalb der Gruppe alternierend und nicht konstant sein. Die sehr effiziente "Tabibitosan"-Methode kann hier (glaube ich) nicht angewendet werden; Die allgemeinere Methode "Gruppenstart" funktioniert. Das habe ich hier verwendet. Beachten Sie, dass ich am Ende die allerletzte Zeile in einer Gruppe auslasse, wenn die Zählung für die Gruppe eine ungerade Zahl ist. (Wir können zwei oder vier oder sechs aufeinanderfolgende Reihen finden, die ein oder zwei oder drei Paare bilden, aber keine ungerade Anzahl von Reihen mit abwechselndem LR). Beachten Sie auch, dass, wenn zwei Zeilen denselben Bezeichner AND LR haben, die zweite Zeile immer eine NEUE Gruppe beginnt. Wenn sie also tatsächlich Teil eines Paares ist (mit der Zeile NACHHER), wird dies von dieser Lösung korrekt erfasst.
Vergleichen Sie dies mit der MATCH_RECOGNIZE-Lösung für Oracle 12 und höher, die ich separat gepostet habe – und schätzen Sie, wie viel einfacher sie ist!
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
;