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

Inclure la valeur RowId dans le tableau imbriqué

ROWID est une pseudo-colonne , il ne fait pas partie de la vue du dictionnaire de données de la table (par exemple, il n'apparaît pas dans dba_tab_columns ), il n'est donc pas inclus dans le %rowtype . Un enregistrement PL/SQL - dont vous construisez une table PL/SQL - n'a pas de stockage physique, donc pas de rowid réel ou pseudo.

Si vous voulez vraiment stocker l'ID de ligne dans un enregistrement/table, vous devrez déclarer le type explicitement :

create or replace package dat_pkg is

    type typ_dat_rec is record (
        data_id     data_test.data_id%type,
        data_value  data_test.data_value%type,
        data_rowid  rowid);

    type typ_dat_tst is table of data_test%rowtype index by pls_integer;

    procedure proc_test (p_dat  typ_dat_tst);

end dat_pkg;
/

Vous ne pouvez pas appeler le champ d'enregistrement simplement rowid comme il s'agit d'un type de données, je l'ai donc préfixé avec data_ mais vous pourriez préférer autre chose. Et puis vous devez utiliser ce nom de champ dans le corps de votre package, évidemment :

create or replace package body dat_pkg is

    procedure proc_test (p_dat  typ_dat_tst)
    is
    begin

        for i in 1..p_dat.count loop

            update  data_test        
            set     data_value  = p_dat(i).data_value  
            where   data_id     = p_dat(i).data_id
            and     rowid       = p_dat(i).data_rowid;

        end loop;

    end proc_test;

end dat_pkg;
/

Vous pouvez, comme vous l'avez suggéré, stocker le type de ligne entier et l'ID de ligne sous la forme de deux champs dans le type d'enregistrement :

create or replace package dat_pkg is

    type typ_dat_rec is record (
        data_rec    data_test%rowtype,
        data_rowid  rowid);

    type typ_dat_tst is table of typ_dat_rec index by pls_integer;

    procedure proc_test (p_dat  typ_dat_tst);

end dat_pkg;
/

mais cela rend la référence aux champs un peu plus gênante :

...
        for i in 1..p_dat.count loop

            update  data_test        
            set     data_value  = p_dat(i).data_rec.data_value  
            where   data_id     = p_dat(i).data_rec.data_id
            and     rowid       = p_dat(i).data_rowid;

        end loop;
...

et cela rendra probablement le remplissage de la collection plus gênant aussi. Comme vous devez de toute façon connaître tous les noms de colonnes/champs pour pouvoir vous y référer dans la boucle, je ne suis pas sûr qu'il y ait beaucoup d'avantages, mais vous trouverez peut-être cela plus propre.

Bien sûr, cela suppose que votre collection est remplie à partir d'un sous-ensemble de données de la table dans la même base de données et même session, car le rowid d'une ligne peut changer avec le temps. Vous pouvez également consulter le forall syntaxe pour remplacer votre for boucle, selon ce que vous faites réellement. (Mais vous devez également déterminer si vous avez besoin de la collection - si vous remplissez simplement la collection et que vous l'utilisez ensuite pour la mise à jour, une seule mise à jour SQL serait encore plus rapide...)