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

mettre à jour plusieurs enregistrements dans plusieurs tables imbriquées dans oracle

Peut-être que la meilleure raison d'éviter les tables imbriquées dans une base de données est qu'elles sont difficiles à utiliser et que la syntaxe est sous-documentée et difficile à comprendre.

Passons à autre chose !

Voici un tableau avec un tableau imbriqué.

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>

Comme vous pouvez le voir, chaque élément de la table imbriquée, l'attribut ID est défini sur zéro dans tous les cas. Ce que nous aimerions faire, c'est les mettre à jour tous. Mais, hélas !

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> 

Il est possible de mettre à jour tous les éléments d'une table imbriquée pour une seule ligne de la table d'exploitation :

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>

Mais la seule façon de faire ça pour toute la table est une boucle PL/SQL. Beurk !

Il existe une alternative :utiliser une table imbriquée Localisateur , via l'indicateur NESTED_TABLE_GET_REFS. C'est une chose particulièrement obscure (ce n'est pas dans le liste principale des astuces ) mais ça fait l'affaire :

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>

Cette astuce nous permet de contourner complètement la table de maintien et de travailler avec la table imbriquée réelle. C'est-à-dire l'objet spécifié dans la clause Nested Table storage :

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