在嵌套表

时间:2017-05-16 17:08:58

标签: sql oracle plsql rowid nested-table

我有以下示例表:

create table data_test
(
    data_id     number,
    data_value  varchar2(100)
);

我想通过以下声明在下面的示例存储过程中将其用作嵌套表参数:

create or replace package dat_pkg is

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

我希望proc_test根据嵌套表的rowid更新data_test行:

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

        end loop;

    end proc_test;

end dat_pkg;
/    

但是我收到错误PLS-00302: component 'ROWID' must be declared,因为它在嵌套表中查找物理列rowid。 当我使用函数rowidtochar()时,会引发同样的错误。

如何在类型声明中包含rowid作为实体列?

1 个答案:

答案 0 :(得分:1)

ROWID is a pseudocolumn,它不是表格的数据字典视图的一部分(例如,它不会出现在dba_tab_columns中),因此它不包含在%rowtype中。 PL / SQL记录 - 你正在构建一个PL / SQL表 - 它没有物理存储,所以没有真正的或伪的rowid。

如果您确实要将行ID存储在记录/表中,则必须明确声明该类型:

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

您不能仅仅将rowid称为记录字段,因为这是一种数据类型,因此我将其作为data_的前缀,但您可能更喜欢其他内容。然后你需要在包体中使用该字段名称,显然:

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

您可以按照建议将整个行类型存储为记录类型中的两个字段:

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

但这使得引用字段更加尴尬:

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

它可能会使集合填充更加尴尬。因为你必须知道所有列/字段名称无论如何都能够在循环中引用它们,我不确定它有多大优势,但你可能会觉得它更整洁。

当然,执行此操作会假定您的集合是从同一个数据库甚至会话中的表中的数据子集填充的,因为行rowid可能会随时间而变化。您可能还需要查看forall语法来替换for循环,具体取决于您的实际操作。 (但是你也应该考虑是否需要集合 - 如果你只是填充集合然后使用它进行更新,那么单个SQL更新会更快...)