Oracle
 sql >> Base de données >  >> RDS >> Oracle

Instruction de mise à jour Oracle avec fonction de groupe

Vous avez deux enregistrements dans chaque table où area est 01 , et vous devez les définir sur des valeurs différentes pour satisfaire la clé primaire - vous ne pouvez pas les définir tous les deux sur la valeur max ou min de la deuxième table, vous ne voulez donc pas vraiment faire de regroupement.

Il ne semble pas y avoir d'autre ordre entre les enregistrements avec la même area , donc je suppose que c'est arbitraire et peu importe quel enregistrement pour chaque area obtient quel branch_code de l'autre table. Si ce n'est pas arbitraire, il faudrait alors préciser les règles...

Une mise à jour corrélée est délicate si vous devez faire correspondre un ordre arbitraire au sein d'un groupe d'enregistrements. Vous avez besoin d'un moyen d'identifier l'ordre des lignes, mais en ajoutant un row_number() colonne aux tables d'origine pour créer une vue en ligne entraînera une erreur ORA-01732.

Vous pouvez cependant utiliser le rowid de la table cible pseudo-colonne ; il vous suffit de faire une jointure supplémentaire dans la corrélation pour obtenir cette même valeur avec le nouveau branch_code . Quelque chose comme :

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;

Ce qui vous donne :

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           

Maintenant, vous n'avez plus besoin de toutes ces colonnes, vous n'avez besoin que du rid (le branch_cp.rowid ) et le branch_cp_2.branch_code corrélé .

Mais vous ne voulez également mettre à jour que lorsqu'il y a une correspondance - pour annuler la nullité des lignes où il n'y a pas de valeur dans l'autre table - vous devrez donc répéter cette jointure dans le exists sous-requête.

C'est plus simple de faire un merge :

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.

Votre tableau contient désormais :

select * from branch_cp;

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

SQL Fiddle .