将集合传递给函数时,数据类型无效

时间:2018-01-12 23:05:57

标签: oracle plsql

CREATE OR REPLACE PACKAGE test_package
IS
  TYPE IDTable IS TABLE OF test_table.id%TYPE;

  TYPE RowIDTable IS TABLE OF VARCHAR2(500);

  FUNCTION delete_rows (row_ids IN RowIDTable) RETURN IDTable;
END test_package;
/

CREATE OR REPLACE PACKAGE BODY test_package
IS
  FUNCTION delete_rows (row_ids IN RowIDTable) RETURN IDTable
  IS
    ids IDTable;
  BEGIN
    DELETE FROM test_table
    WHERE ROWIDTONCHAR(rowid) IN (SELECT * FROM TABLE(row_ids))
    RETURNING id BULK COLLECT INTO ids;

    COMMIT;

    RETURN ids;
  END;
END test_package;
/

使用上述功能时,我不断获得ORA-00902: invalid datatype。我做错了什么?

错误指向DELETE语句。

2 个答案:

答案 0 :(得分:1)

看起来问题是您正在使用的集合类型。因为它是一个包级PL / SQL集合类型。

The ruby-plsql documentation表示它支持PL / SQL记录,但表和varray类型不引用PL / SQL - 表明它们必须是SQL(即模式级)用户定义类型。

即使图中没有Ruby,当运行时始终使用相同的包定义类型时,也会抛出invalid-datatype错误。在12c之前,您根本无法在SQL语句中使用PL / SQL集合,并且在这种情况下它似乎仍然不起作用。

如果从PL / SQL类型更改为模式级类型,则此代码有效,在此示例中为内置varray类型:

CREATE OR REPLACE PACKAGE test_package
IS
  TYPE IDTable IS TABLE OF test_table.id%TYPE;

  --TYPE RowIDTable IS TABLE OF VARCHAR2(500); —- not used now

  FUNCTION delete_rows (row_ids IN sys.odcivarchar2list) RETURN IDTable;
END test_package;
/

CREATE OR REPLACE PACKAGE BODY test_package
IS
  FUNCTION delete_rows (row_ids IN sys.odcivarchar2list) RETURN IDTable
  IS
    ids IDTable;
  BEGIN
    DELETE FROM test_table
    WHERE ROWIDTONCHAR(rowid) IN (SELECT * FROM TABLE(row_ids))
    RETURNING id BULK COLLECT INTO ids;

    COMMIT;

    RETURN ids;
  END;
END test_package;
/

您可以使用匿名阻止测试:

declare
  ids test_package.idtable;
begin
  ids := test_package.delete_rows(sys.odcivarchar2list('ROWID1', 'ROWID2'));
end;
/

转换表中的每个rowid会更有效,所以你可以这样做:

WHERE rowid IN (SELECT CHARTOROWID(column_value) FROM TABLE(row_ids))

但请记住,rowid并不总是不可变的 - 希望您传入的引用最近足以始终有效。否则,使用主键而不是rowid。

我不知道Ruby,所以不完全确定如何翻译;再次从文档看起来像:

plsql.test_package.delete_rows(['ROWID1','ROWID2'])

...但不确定它将如何处理返回的(PL / SQL)表类型。这可能也需要是模式级表类型。 (如果你想创建自己的类型,你可以创建类型为varrays或嵌套表,这可能是一个好主意。)

答案 1 :(得分:0)

为什么不在RowIDTable上使用TABLE OF ROWID而不是TABLE OF VARCHAR2(500)

像这样:

TYPE RowIDTable IS TABLE OF ROWID;

然后你就不必施放ROWID:

DELETE FROM test_table tbl
WHERE tbl.rowid IN (SELECT column_value FROM TABLE(row_ids))
RETURNING id BULK COLLECT INTO ids;

希望这有帮助。