Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Instrução de atualização do Oracle com função de grupo


Você tem dois registros em cada tabela onde area é 01 , e você precisa defini-los com valores diferentes para satisfazer a chave primária - você não pode defini-los para o valor máximo ou mínimo da segunda tabela, então você realmente não deseja fazer nenhum agrupamento.

Não parece haver nenhuma outra ordenação entre registros com a mesma area , então vou assumir que é arbitrário e não importa qual registro para cada area obtém qual branch_code da outra mesa. Se não for arbitrário, as regras precisariam ser especificadas ...

Uma atualização correlacionada é complicada se você precisar corresponder em uma ordem arbitrária dentro de um grupo de registros. Você precisa de alguma maneira de identificar a ordem das linhas, mas adicionando um row_number() coluna para as tabelas originais para criar uma visualização em linha levará a um erro ORA-01732.

Você pode, no entanto, usar o rowid da tabela de destino pseudocoluna; você só precisa fazer uma junção adicional na correlação para obter o mesmo valor junto com o novo branch_code . Algo como:
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;

Que lhe dá:
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           

Agora você não precisa de todas essas colunas, você só precisa do rid (o branch_cp.rowid ) e o branch_cp_2.branch_code correlacionado .

Mas você também deseja atualizar apenas quando houver uma correspondência - para anular a anulação de quaisquer linhas em que não haja valor na outra tabela - então você teria que repetir essa junção no exists subconsulta.

É mais simples fazer um 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.

Sua mesa agora tem:
select * from branch_cp;

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

SQL Fiddle .