每天早上,我都会将大量表从生产数据库复制到我的数据仓库中。这是我在每次截断 + 插入之前运行的“检查和修复”程序。
procedure check_and_fix_table(p_naam in varchar2)
/**
* check if columns have changed on PROD and create and execute the matching ALTER TABLE statement
*/
is
v_coltype varchar2(100);
v_sql varchar2(200);
function check_column(p_column in varchar2)
return boolean
is
v_dummy number;
begin
select 1 into v_dummy
from user_tab_cols tc
where tc.table_name = upper(p_naam)
and tc.column_name = p_column;
return true;
exception
when no_data_found then return false;
end;
begin
-- loop through all columns that are altered (if nothing altered, then nothing will happen
for i in (select tc.column_name
, tc.data_type
, tc.data_length
, tc.data_precision
from user_tab_cols@DB_LINK_TO_PRODUCTION tc
where tc.table_name = upper(p_naam)
and tc.column_name not like 'SYS_NC%' -- These columns are created by oracle for function based indexes
minus
select tc.column_name
, tc.data_type
, tc.data_length
, tc.data_precision
from user_tab_cols tc
where tc.table_name = upper(p_naam))
loop
-- create column type
if i.data_type in ('CHAR','VARCHAR2') then
v_coltype := i.data_type||'('||i.data_length||')';
elsif i.data_type = 'NUMBER' then
if i.data_precision is not null then
v_coltype := i.data_type||'('||i.data_precision||')';
else
v_coltype := i.data_type;
end if;
else -- DATE, CLOB, BLOB, etc
v_coltype := i.data_type;
end if;
-- check if the column is altered or added
if check_column(i.column_name) then
-- execute the ALTER TABLE to fix the column
v_sql := 'alter table '||p_naam||' modify '||i.column_name||' '||v_coltype;
else
-- add new column
v_sql := 'alter table '||p_naam||' add '||i.column_name||' '||v_coltype;
end if;
execute immediate v_sql;
-- logging change
prc_log(c_procedureid, 1, p_naam||' changed. Fixed by executing: '||v_sql);
end loop;
exception
when others then
prc_log(c_procedureid, 3, 'Error at copy_package.check_and_fix_table - '||substr(sqlerrm, 0, 1900));
end;
然后在我的主程序中,我像这样使用它(其中 p_naam 是作为参数传递给程序的表名):
check_and_fix_table(p_naam);
-- full copy of table from PROD
execute immediate 'truncate table ' || p_naam;
execute immediate 'insert /*+append*/ into ' || p_naam || ' select * from ' || p_naam || '@DB_LINK_TO_PRODUCTION';
希望这可以帮助 :)