问:关于Oracle数据库,我有以下几个问题想请教:
1、请问为何我们不能再自定义函数中调用一个存储过程呢?
2、请问能不能再触发器内部创建一个表?
答:当然可以在自定义函数中调用存储过程,请参考以下例子:
以下是引用片段:
SQL> create table test_tab (tab_id number);
Table created.
SQL> insert into test_tab values (10);
1 row created.
SQL> insert into test_tab values (20);
1 row created.
SQL> commit;
SQL> create table test_tab_audit (tab_id number, aud_date date);
Table created.
SQL> create or replace procedure test_proc (id number)
2 as
3 begin
4 null;
5 end;
6 /
Procedure created.
SQL> create or replace function test_fn(v_id number)
2 return number
3 as
4 begin
5 test_proc(v_id);
6 return v_id+1;
7 end;
8 /
Function created.
SQL> select tab_id,test_fn(tab_id) from test_tab;
TAB_ID TEST_FN(TAB_ID)
---------- ---------------
10 11
20 21
当函数从SELECT语句调用的时候,你用存储过程能做的就非常有限。你不能在查询中使用DML或者DDL,否则可能会抛出以下的错误:ORA-14551: cannot perform a DML operation inside a query
ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML
但是下面的例子中,调用存储过程就不会出现问题:
SQL> create or replace procedure test_proc (id number)
2 as
3 begin
4 insert into test_tab_audit values (id,sysdate);
5 commit;
6 end;
7 /
Procedure created.
SQL> declare
2 val number;
3 begin
4 val:=test_fn(10);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select * from test_tab_audit;
TAB_ID AUD_DATE
---------- ---------
10 30-JUL-12
而针对你的第二个关于触发器的问题,答案是肯定的,你可以创建表。使用EXECUTE IMMEDIATE命令即可。
SQL> CREATE TRIGGER test_tab_trigger
2 BEFORE INSERT ON test_tab
3 FOR EACH ROW
4 BEGIN
5 EXECUTE IMMEDIATE 'create table another table (id number)';
6 END;
7 /
Trigger created.
然而真正你需要了解的问题应该是:该不该在触发器中创建一个表?通常来说,动态创建一个表是不提倡的,应用系统的表应该预先创建。此外,每一个INSERT、UPDATE或者DELETE启动触发器的时候,都会消耗很长的时间,因为你需要等待DML命令完成之前的表创建完毕。所以我们认为在触发器中写这些代码是不合适的。