sql >> Database >  >> RDS >> Oracle

Oracle update-instructie met groepsfunctie

Je hebt twee records in elke tabel waar area is 01 , en je moet ze op verschillende waarden instellen om aan de primaire sleutel te voldoen - je kunt ze niet allebei instellen op de max of min waarde uit de tweede tabel, dus je wilt niet echt groeperen.

Er lijkt geen andere volgorde te zijn tussen records met hetzelfde area , dus ik ga ervan uit dat het willekeurig is en dat het niet uitmaakt welk record voor elk area krijgt welke branch_code van de andere tafel. Als het niet willekeurig is, moeten de regels worden gespecificeerd...

Een gecorreleerde update is lastig als u op een willekeurige volgorde binnen een groep records moet matchen. Je hebt een manier nodig om de rijvolgorde te identificeren, maar voeg een row_number() toe kolom naar de originele tabellen om een ​​inline-weergave te maken, leidt tot een ORA-01732-fout.

U kunt echter de rowid . van de doeltabel gebruiken pseudokolom; je hoeft alleen maar een extra join in de correlatie te doen om dezelfde waarde te krijgen samen met de nieuwe branch_code . Iets als:

select bc.rid,
  bc.area,
  bc.branch_code,
  bc.branch_name,
  bc2.area,
  bc2.branch_code,
  bc2.branch_name
from (
  select bc.*,
    bc.rowid as rid,
    row_number() over (partition by bc.area order by bc.branch_code) as rn
  from branch_cp bc
) bc
join (
  select bc2.*,
    row_number() over (partition by bc2.area order by bc2.branch_code) as rn
  from branch_cp_2 bc2
) bc2
on bc2.area = bc.area
and bc2.rn = bc.rn;

Dat geeft je:

RID                AREA  BRANCH_CODE BRANCH_NAME AREA  BRANCH_CODE BRANCH_NAME
------------------ ----- ----------- ----------- ----- ----------- -----------
AAAwy+AAEAAAA0DAAA 01    01          A           01    04          D           
AAAwy+AAEAAAA0DAAB 01    02          B           01    05          E           
AAAwy+AAEAAAA0DAAC 03    03          C           03    06          F           

Nu heb je eigenlijk niet al die kolommen nodig, je hebt alleen de rid . nodig (de branch_cp.rowid ) en de gecorreleerde branch_cp_2.branch_code .

Maar je wilt ook alleen updaten als er een overeenkomst is - om het ongeldig maken van rijen waar geen waarde in de andere tabel staat - dus je zou die join moeten herhalen in de exists subquery.

Het is eenvoudiger om een ​​merge te doen :

merge into branch_cp bc
using (
  select bc.rid,
      bc2.branch_code
    from (
      select bc.*,
        bc.rowid as rid,
        row_number() over (partition by bc.area order by bc.branch_code) as rn
      from branch_cp bc
    ) bc
    join (
      select bc2.*,
        row_number() over (partition by bc2.area order by bc2.branch_code) as rn
      from branch_cp_2 bc2
    ) bc2
    on bc2.area = bc.area
    and bc2.rn = bc.rn
) bc2
on (bc.rowid = bc2.rid)
when matched then update set bc.branch_code = bc2.branch_code;

3 rows merged.

Uw tafel heeft nu:

select * from branch_cp;

AREA  BRANCH_CODE BRANCH_NAME
----- ----------- -----------
01    04          A           
01    05          B           
03    06          C           

SQL Fiddle .




  1. JDBC-transactie met gebruikersinvoer

  2. Problemen met GROEP VOOR GEVAL

  3. Het ACID-model voor databasebeheer begrijpen

  4. Kom naar Amsterdam voor een Meetup met OptimaData &VidaXL