sql >> Base de Datos >  >> RDS >> Oracle

actualizar múltiples registros en múltiples tablas anidadas en Oracle

Quizás la mejor razón para evitar las tablas anidadas en una base de datos es que es difícil trabajar con ellas y la sintaxis no está bien documentada y es difícil de asimilar.

¡Adelante!

Aquí hay una tabla con una tabla anidada.

SQL> select f.force_name, t.id, t.name
  2  from transformer_forces f, table(f.force_members) t
  3  /

FORCE_NAME         ID NAME
---------- ---------- --------------------
Autobot             0 Metroplex
Autobot             0 Optimus Prime
Autobot             0 Rodimus
Decepticon          0 Galvatron
Decepticon          0 Megatron
Decepticon          0 Starscream
Dinobot             0 Grimlock
Dinobot             0 Swoop
Dinobot             0 Snarl

9 rows selected.

SQL>

Como puede ver, en cada elemento de la tabla anidada, el atributo ID se establece en cero en todos los casos. Lo que nos gustaría hacer es actualizarlos todos. Pero, ¡ay!

SQL> update table
  2   ( select force_members from transformer_forces ) t
  3  set t.id = rownum
  4  /
 ( select force_members from transformer_forces ) t
   *
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row


SQL> 

Es posible actualizar todos los elementos en una tabla anidada para una sola fila en la tabla de espera:

SQL> update table
  2       ( select force_members from transformer_forces
  3         where force_name = 'Autobot') t
  4      set t.id = rownum
  5  /

3 rows updated.

SQL>

Pero la única manera de hacer eso para toda la tabla es un bucle PL/SQL. ¡Puaj!

Hay una alternativa:use una tabla anidada Localizador , a través de la sugerencia NESTED_TABLE_GET_REFS. Esto es algo particularmente oscuro (no está en lista principal de sugerencias ) pero funciona:

SQL> update /*+ NESTED_TABLE_GET_REFS */ force_members_nt
  2  set id = rownum
  3  /

9 rows updated.

SQL> select f.force_name, t.id, t.name
  2  from transformer_forces f, table(f.force_members) t
  3  /

FORCE_NAME         ID NAME
---------- ---------- --------------------
Autobot             1 Metroplex
Autobot             2 Optimus Prime
Autobot             3 Rodimus
Decepticon          4 Galvatron
Decepticon          5 Megatron
Decepticon          6 Starscream
Dinobot             7 Grimlock
Dinobot             8 Swoop
Dinobot             9 Snarl

9 rows selected.

SQL>

Esta sugerencia nos permite omitir la tabla de espera por completo y trabajar con la tabla anidada real. Es decir, el objeto especificado en la cláusula de almacenamiento de la tabla anidada:

create table transformer_forces (
    force_name varchar2(10)
    , force_members transformers_nt)
nested table force_members store as force_members_nt return as value;
                                    ^^^^^^^^^^^^^^^^