Oracle
 sql >> Database >  >> RDS >> Oracle

Includi il valore RowId nella tabella nidificata

ROWID è una pseudocolonna , non fa parte della vista del dizionario dei dati della tabella (ad es. non appare in dba_tab_columns ), quindi non è incluso nel %rowtype . Un record PL/SQL, che è ciò di cui stai costruendo una tabella PL/SQL, non ha memoria fisica, quindi nessun ID reale o pseudo.

Se vuoi davvero memorizzare l'ID riga in un record/tabella dovresti dichiarare il tipo in modo esplicito:

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;
/

Non puoi chiamare il campo del record solo rowid poiché è un tipo di dati, quindi l'ho preceduto con data_ ma potresti preferire qualcos'altro. E poi devi usare quel nome di campo nel corpo del tuo pacchetto, ovviamente:

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;
/

Potresti, come hai suggerito, memorizzare l'intero tipo di riga e l'ID riga come due campi nel tipo di record:

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;
/

ma questo rende un po' più imbarazzante fare riferimento ai campi:

...
        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;
...

e probabilmente renderà anche più imbarazzante popolare la raccolta. Dato che devi comunque conoscere tutti i nomi di colonne/campi per poterli fare riferimento nel ciclo, non sono sicuro che ci siano molti vantaggi, ma potresti trovarlo più ordinato.

Ovviamente, fare questo presuppone che la tua raccolta venga popolata da un sottoinsieme di dati dalla tabella nello stesso DB e persino nella stessa sessione, poiché il rowid di una riga può cambiare nel tempo. Potresti anche voler esaminare il forall sintassi per sostituire il tuo for loop, a seconda di cosa stai facendo veramente. (Ma dovresti anche considerare se hai bisogno della raccolta:se stai solo popolando la raccolta e quindi la usi per l'aggiornamento, un singolo aggiornamento SQL sarebbe ancora più veloce...)