在嵌套中包含 RowId 值 Table

Include RowId value in Nested Table

我有以下示例 table:

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

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

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 根据嵌套 table 的 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 因为它在嵌套 Table 中寻找物理列 rowid。 当我使用函数 rowidtochar().

时出现同样的错误

如何在类型声明中包含 rowid 作为物理列?

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

如果您真的想将行 ID 存储在 record/table 中,您必须显式声明类型:

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

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

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

而且它可能也会使填充集合变得更加尴尬。因为无论如何您都必须知道所有 column/field 名称才能在循环中引用它们,所以我不确定这有什么好处,但您可能会发现它更简洁。

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