user_tab_columns 什么时候更新?
When does user_tab_columns get updated?
在另一个 中,我尝试创建一个 hist table,它保留来自给定 table 的日志。有了那个问题的答案,我试图创造一些新的东西。
由于无法在 table 或视图上创建系统触发器,因此我创建了一个 DDL 触发器,如下所示:
create or replace trigger ident_hist_trig after alter on schema
declare
v_table varchar2(30);
begin
select upper(ora_dict_obj_name) into v_table from dual;
if (v_table = 'Z_IDENT') then
prc_create_hist_tabel('z_ident_hist', 'z_ident');
elsif (v_table = 'D_IDENT') then
prc_create_hist_tabel('d_ident_hist', 'd_ident');
elsif (v_table = 'X_IDENT') then
prc_create_hist_tabel('x_ident_hist', 'x_ident');
else
null;
end if;
end;
/
程序 prc_create_hist_tabel 如下所示:
create or replace procedure prc_create_hist_tabel(p_naam_hist_tabel in varchar2, p_naam_tabel in varchar2) is
cursor c is
select 'alter table ' || p_naam_hist_tabel || ' add ' || column_name || ' ' || data_type || case when data_type = 'DATE' then null else '(' || data_length || ')' end lijn
from user_tab_columns
where TABLE_NAME = upper(p_naam_tabel)
and column_name not in (select column_name from user_tab_columns where table_name = upper(p_naam_hist_tabel));
v_dummy number(1);
cursor trig is
select column_name || ',' kolom, ':old.' || column_name || ',' old
from user_tab_columns
where table_name = upper(p_naam_tabel);
v_trigger_sql varchar2(32767);
begin
begin
select 1 into v_dummy
from user_tab_columns
where TABLE_NAME = upper(p_naam_hist_tabel)
group by 1;
exception when no_data_found then
execute immediate 'create table ' || p_naam_hist_tabel || ' (wijziger varchar2(60) default user, wijzigdatum date default sysdate, constraint pk_' || p_naam_hist_tabel || ' primary key (wijziger, wijzigdatum))';
end;
dbms_output.put_line('BBB');
for i in c
loop
begin
dbms_output.put_line(i.lijn);
execute immediate i.lijn;
exception when others then
dbms_output.put_line(i.lijn);
end;
end loop;
v_trigger_sql := 'create or replace trigger ' || p_naam_tabel || '_hist_trig after update on ' || p_naam_tabel || ' for each row begin insert into ' || p_naam_hist_tabel || ' (';
for v_lijn in trig
loop
v_trigger_sql := v_trigger_sql || v_lijn.kolom;
end loop;
v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1);
v_trigger_sql := v_trigger_sql || ') values (';
for v_lijn in trig
loop
v_trigger_sql := v_trigger_sql || v_lijn.old;
end loop;
v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1);
v_trigger_sql := v_trigger_sql || '); end;';
execute immediate v_trigger_sql;
end;
/
简而言之,该功能的作用是维护历史 table。如果它不存在,它将创建一个,如果它存在,它将向其中添加新列。该过程还创建了一个新触发器,它将在更新后将旧值写入历史记录 table。
但是当我更改 table 中的一个 x_ident、z_ident 或 d_ident 时,光标 c 将 return 什么都没有(我可以检查当我遍历它时打印出来的那个)。尽管在执行 select after 时我更改了我的 table,但我确实得到了结果。
我改变 table d_ident 得到的结果是:
BBB
d_ident: Table altered.
但我想应该是相反的,我认为程序 prc_create_hist_tabel 是在 alter table 实际关闭之前执行的,我想我应该得到这样的结果:
d_ident: Table altered.
BBB
如有任何帮助,我们将不胜感激。我试图在 user_tab_columns 上的插入时创建触发器,但这给了我 ORA-25001:无法在视图上创建此触发器类型。
我也试过睡眠命令,但也没用。
这行不通。即使您能够在触发器中获取要添加到 table 的列,如果您尝试在触发器中实际执行 DDL,您也会收到错误消息,指出触发器中不允许 DDL .
我希望解决此问题的正确方法是将调用 prc_create_hist_tabel
作为促销脚本的一部分。合理的系统不会随意向 table 添加列。 DDL 是存在于源代码控制中并在测试后部署的升级的一部分。如果您的推广脚本无法修改历史记录 table,您会在测试期间发现您错过了一个步骤,并且更改永远不会投入生产。自动发生更改意味着它们不在更改控制中,这使得从更改控制进行构建变得更加困难。
如果您决定自动执行此操作,您的触发器将需要提交一个作业,实际上使用 dbms_job
而不是调用该过程的较新的 dbms_scheduler
。该作业将 运行 在 DDL 触发器成为已提交事务的一部分之后。届时,该列将在 dba_tab_columns
中可见。而你的工作是免费做 DDL 的。
在另一个
由于无法在 table 或视图上创建系统触发器,因此我创建了一个 DDL 触发器,如下所示:
create or replace trigger ident_hist_trig after alter on schema
declare
v_table varchar2(30);
begin
select upper(ora_dict_obj_name) into v_table from dual;
if (v_table = 'Z_IDENT') then
prc_create_hist_tabel('z_ident_hist', 'z_ident');
elsif (v_table = 'D_IDENT') then
prc_create_hist_tabel('d_ident_hist', 'd_ident');
elsif (v_table = 'X_IDENT') then
prc_create_hist_tabel('x_ident_hist', 'x_ident');
else
null;
end if;
end;
/
程序 prc_create_hist_tabel 如下所示:
create or replace procedure prc_create_hist_tabel(p_naam_hist_tabel in varchar2, p_naam_tabel in varchar2) is
cursor c is
select 'alter table ' || p_naam_hist_tabel || ' add ' || column_name || ' ' || data_type || case when data_type = 'DATE' then null else '(' || data_length || ')' end lijn
from user_tab_columns
where TABLE_NAME = upper(p_naam_tabel)
and column_name not in (select column_name from user_tab_columns where table_name = upper(p_naam_hist_tabel));
v_dummy number(1);
cursor trig is
select column_name || ',' kolom, ':old.' || column_name || ',' old
from user_tab_columns
where table_name = upper(p_naam_tabel);
v_trigger_sql varchar2(32767);
begin
begin
select 1 into v_dummy
from user_tab_columns
where TABLE_NAME = upper(p_naam_hist_tabel)
group by 1;
exception when no_data_found then
execute immediate 'create table ' || p_naam_hist_tabel || ' (wijziger varchar2(60) default user, wijzigdatum date default sysdate, constraint pk_' || p_naam_hist_tabel || ' primary key (wijziger, wijzigdatum))';
end;
dbms_output.put_line('BBB');
for i in c
loop
begin
dbms_output.put_line(i.lijn);
execute immediate i.lijn;
exception when others then
dbms_output.put_line(i.lijn);
end;
end loop;
v_trigger_sql := 'create or replace trigger ' || p_naam_tabel || '_hist_trig after update on ' || p_naam_tabel || ' for each row begin insert into ' || p_naam_hist_tabel || ' (';
for v_lijn in trig
loop
v_trigger_sql := v_trigger_sql || v_lijn.kolom;
end loop;
v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1);
v_trigger_sql := v_trigger_sql || ') values (';
for v_lijn in trig
loop
v_trigger_sql := v_trigger_sql || v_lijn.old;
end loop;
v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1);
v_trigger_sql := v_trigger_sql || '); end;';
execute immediate v_trigger_sql;
end;
/
简而言之,该功能的作用是维护历史 table。如果它不存在,它将创建一个,如果它存在,它将向其中添加新列。该过程还创建了一个新触发器,它将在更新后将旧值写入历史记录 table。
但是当我更改 table 中的一个 x_ident、z_ident 或 d_ident 时,光标 c 将 return 什么都没有(我可以检查当我遍历它时打印出来的那个)。尽管在执行 select after 时我更改了我的 table,但我确实得到了结果。
我改变 table d_ident 得到的结果是:
BBB
d_ident: Table altered.
但我想应该是相反的,我认为程序 prc_create_hist_tabel 是在 alter table 实际关闭之前执行的,我想我应该得到这样的结果:
d_ident: Table altered.
BBB
如有任何帮助,我们将不胜感激。我试图在 user_tab_columns 上的插入时创建触发器,但这给了我 ORA-25001:无法在视图上创建此触发器类型。
我也试过睡眠命令,但也没用。
这行不通。即使您能够在触发器中获取要添加到 table 的列,如果您尝试在触发器中实际执行 DDL,您也会收到错误消息,指出触发器中不允许 DDL .
我希望解决此问题的正确方法是将调用 prc_create_hist_tabel
作为促销脚本的一部分。合理的系统不会随意向 table 添加列。 DDL 是存在于源代码控制中并在测试后部署的升级的一部分。如果您的推广脚本无法修改历史记录 table,您会在测试期间发现您错过了一个步骤,并且更改永远不会投入生产。自动发生更改意味着它们不在更改控制中,这使得从更改控制进行构建变得更加困难。
如果您决定自动执行此操作,您的触发器将需要提交一个作业,实际上使用 dbms_job
而不是调用该过程的较新的 dbms_scheduler
。该作业将 运行 在 DDL 触发器成为已提交事务的一部分之后。届时,该列将在 dba_tab_columns
中可见。而你的工作是免费做 DDL 的。