我是PL / SQL的新手并试图创建一个引用表行的对象:
CREATE OR REPLACE TYPE my_object AS OBJECT(
table_row my_table%ROWTYPE
);
编译器给出错误消息PLS-00329。 好的,现在我知道我不能引用像这样的表格。但是有解决方法吗?
答案 0 :(得分:5)
您必须列出对象类型声明中的所有字段。你提到你担心容易出错。您可以通过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
。
答案 1 :(得分:0)
听起来很方便,我认为类型的语法不可能有任何类型,因为类型必须提供SQL接口 - 你必须能够描述类型并查看其属性列表,属性需要是发布在user_type_attrs中,您必须能够从中创建子类型和对象关系表和列,在查询中使用它并查看列投影等。
使用select *
创建视图时,列列表会在创建时展开,但如果稍后更改表格则不会重建。因此,即使Oracle确实提供了一种类似于类型的方法,我怀疑它们必须遵循相同的模式,即在创建时简单地生成列表,然后将其保留给您进行维护,以避免管理依赖项的复杂性和级联失效,特别是当类型本身具有复杂的依赖关系时,type evolution周围的限制。