sql >> Database >  >> RDS >> Oracle

Oracle SQL Pair Rechts Links Volgnummers met Identifiers

Hier is een oplossing die meer in het algemeen werkt, zelfs als de paren niet noodzakelijk direct naast elkaar worden gevonden. (Als dat in feite VEREIST is, als onderdelen niet kunnen worden gekoppeld als hun ID's niet opeenvolgend zijn, kan die voorwaarde aan de zoekopdracht worden toegevoegd.)

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
;

Uitvoer :

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 

Uitleg:In de inner query voeg ik nog twee kolommen toe aan de initiële gegevens. Een, rn , telt afzonderlijk (beginnend bij 1 en oplopend met 1) voor elke identifier, afzonderlijk voor 'L' en voor 'R'. Dit wordt gebruikt om de paren te vormen. En, ct geeft de minste van de totale tellingen voor 'L' en 'R' voor elke identifier. In de buitenste query filter ik gewoon alle rijen uit waar rn > ct - dat zijn de rijen zonder paar in de begintabel. Wat overblijft zijn de paren.

TOEGEVOEGD :Met de aanvullende voorwaarde dat een paar moet worden gevormd uit "opeenvolgende" rijen (zoals gemeten door de id kolom), wordt dit een interessantere vraag. Het is een gaps-and-islands-probleem (identificeer groepen opeenvolgende rijen met hetzelfde kenmerk), maar met een twist:de LR waarde moet afwisselend zijn binnen de groep, in plaats van constant. De zeer efficiënte "tabibitosan"-methode kan hier niet worden toegepast (denk ik); de "start of group"-methode, die meer algemeen is, werkt wel. Dit is wat ik hier heb gebruikt. Merk op dat ik uiteindelijk de allerlaatste rij in een groep weglaat, als de telling voor de groep een oneven getal is. (We kunnen twee, of vier, of zes opeenvolgende rijen vinden die een of twee of drie paren vormen, maar geen oneven aantal rijen met afwisselende LR). Merk ook op dat als twee rijen dezelfde identifier EN LR hebben, de tweede rij altijd een NIEUWE groep zal starten, dus als het in feite deel uitmaakt van een paar (met de rij NA ​​erna), wordt dat correct opgevangen door deze oplossing.

Vergelijk dit met de MATCH_RECOGNIZE-oplossing voor Oracle 12 en hoger die ik afzonderlijk heb gepost - en waardeer hoeveel eenvoudiger het is!

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
;


  1. Wat zou een goede manier zijn om de QueryBuilder-ketenmethoden van TypeORM te testen?

  2. Is een MySQL-primaire sleutel al in een soort standaardvolgorde?

  3. django+mysql='DatabaseWrapper'-object heeft geen attribuut 'Database'-fout

  4. Oracle Forms in R12/R12.2