对象类型中 %ROWTYPE 的解决方法
Posted
技术标签:
【中文标题】对象类型中 %ROWTYPE 的解决方法【英文标题】:Workaround for %ROWTYPE in Object type 【发布时间】:2017-02-20 11:00:29 【问题描述】:我是 PL/SQL 新手,并试图创建一个引用表行的对象:
CREATE OR REPLACE TYPE my_object AS OBJECT(
table_row my_table%ROWTYPE
);
编译器给了我错误信息 PLS-00329。 好的,现在我知道我不允许引用这样的表格。但是有解决办法吗?
【问题讨论】:
没有。您必须明确列出对象中的每个字段。我不确定“对表格行的引用”是什么意思-您的意思是对象字段与表格列匹配吗?对象有一个字段,其值以某种方式引用表中的特定行? 我们有一些程序可以从不同的表中加载行,现在我想创建一个对象来操作这些行。不同类型的算法总是相同的,所以我希望通过继承来解决这个问题。但我不想列出每个字段,因为在更改表架构的情况下似乎很容易出错。 您确定需要模式级对象类型,而不仅仅是 PL/SQL 记录类型吗? (您可以基于 table%rowtype 定义 PL/SQL 集合,然后批量选择这些集合。)取决于您需要执行的操作。 好吧,我想使用一些面向对象的特性,比如覆盖函数。我一开始不想用 PL/SQL 解决这个问题,但我必须……所以可能我必须列出每个字段。感谢您的帮助! 【参考方案1】:您必须列出对象类型声明中的所有字段。你提到你担心这容易出错。您可以通过 PL/SQL 块(或将表和对象名称传递到其中的过程)半自动化对象创建。
假设您有一个表定义为;
CREATE TABLE my_table (
ID NUMBER(38),
col_1 DATE,
col_2 NUMBER(3, 2),
col_3 VARCHAR2(10),
col_4 CLOB
);
您可以从数据字典中提取列名和数据类型并构建您的对象创建语句:
DECLARE
v_stmt VARCHAR2(4000);
BEGIN
v_stmt := 'CREATE OR REPLACE TYPE my_object AS OBJECT(';
FOR r IN (
SELECT column_name,
CAST (data_type || CASE
WHEN data_type IN ('VARCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW', 'CHAR')
THEN '(' || data_length || ')'
WHEN data_type IN ('NUMBER')
AND (data_precision IS NOT NULL OR data_scale IS NOT NULL)
THEN '(' || data_precision || CASE
WHEN data_scale > 0 THEN ',' || data_scale
END || ')'
END AS VARCHAR2(30)) AS data_type,
CASE WHEN column_id < MAX(column_id) OVER () THEN ',' END AS comma
FROM user_tab_columns
WHERE table_name = 'MY_TABLE'
ORDER BY column_id
)
LOOP
v_stmt := v_stmt || r.column_name || ' ' || r.data_type || r.comma;
END LOOP;
v_stmt := v_stmt || ')';
dbms_output.put_line(v_stmt); -- just for debugging
EXECUTE IMMEDIATE v_stmt;
END;
/
如果你愿意,你也可以提取和使用可空标志,但它在这里可能没有用。 (这改编自a describe
replacement。可能有一些数据类型没有被正确处理,但它涵盖了常见的数据类型;如果您有带有 UDT 或其他奇怪的列,则需要扩展以正确包含这些数据类型。)
dbms_output
只是显示生成的语句以便于调试:
CREATE OR REPLACE TYPE my_object AS OBJECT(ID NUMBER(38),COL_1 DATE,COL_2 NUMBER(3,2),COL_3 VARCHAR2(10),COL_4 CLOB)
PL/SQL procedure successfully completed.
由于该语句也被执行,对象被创建:
desc my_object;
Name Null? Type
----- ----- ------------
ID NUMBER(38)
COL_1 DATE
COL_2 NUMBER(3,2)
COL_3 VARCHAR2(10)
COL_4 CLOB
如果您想添加函数,您可以使用生成的 create 语句作为起点,并在手动运行之前对其进行编辑以添加您需要的任何内容,而不是使用 execute immediate
。
【讨论】:
【参考方案2】:听起来很方便,但我认为类型不可能有任何这样的语法,因为类型必须提供一个 SQL 接口——你必须能够描述类型并查看它的属性列表,属性需要是在 user_type_attrs 中发布,您必须能够从中创建子类型和对象关系表和列,在查询中使用它并查看列投影等。
当您使用select *
创建视图时,列列表会在创建时展开,但如果您稍后更改表,则不会重新构建。因此,即使 Oracle 确实提供了一种对类型执行类似操作的方法,我怀疑它们也必须遵循相同的模式,即在创建时简单地生成列表,然后将其留给您维护,以避免管理依赖项和级联失效,特别是考虑到 type evolution 周围的限制,当类型本身具有复杂的依赖关系时。
【讨论】:
以上是关于对象类型中 %ROWTYPE 的解决方法的主要内容,如果未能解决你的问题,请参考以下文章