在我的架构中,我将大约250个表从SQL Server迁移到Oracle。问题是,没有为任何这些表创建序列或触发器。
是否有一种简单的方法可以生成所有表序列和触发器,而不是手动为每个表执行此操作?
我需要的序列的一个例子是:
CREATE SEQUENCE "SYSTEM"."SEC_USERS_ID_SEQ"
MINVALUE 0 MAXVALUE 999999999999999999999999
INCREMENT BY 1
START WITH 23
CACHE 20
NOORDER NOCYCLE NOPARTITION;
触发器:
create or replace TRIGGER SEC_USERS_TRIG
before INSERT
ON "SYSTEM"."SEC_USERS"
FOR EACH row
BEGIN
IF inserting THEN
IF :NEW."ID" IS NULL THEN
SELECT SEC_USERS_ID_SEQ.nextval INTO :NEW."ID" FROM dual;
END IF;
END IF;
END;
答案 0 :(得分:2)
我们可以使用Oracle数据字典视图(相当于MSSQL INFORMATION_SCHEMA)生成脚本。 Find out more。
此示例生成CREATE SEQUENCE语句。我已按照您的示例接受了默认值,但不需要对其进行编码。序列名称源自与列名连接的表名,后缀为" _SEQ"。注意Oracle's thirty character limit on object names!
此循环动态查询表以获取主键列的当前最大值,该列用于派生STARTS WITH子句。
declare
curr_mx number;
begin
for lrec in ( select ucc.table_name
, ucc.column_name
from user_constraints uc
join user_cons_columns ucc
on ucc.table_name = uc.table_name
and ucc.constraint_name = uc.constraint_name
join user_tab_columns utc
on utc.table_name = ucc.table_name
and utc.column_name = ucc.column_name
where uc.constraint_type = 'P' -- primary key
and utc.data_type = 'NUMBER' -- only numeric columns
)
loop
execute immediate 'select max ('|| lrec.column_name ||') from ' ||lrec.table_name
into curr_mx;
if curr_mx is null then
curr_mx := 0;
end if;
dbms_output.put_line('CREATE SEQUENCE "'|| user || '"."'
|| lrec.table_name ||'_'|| lrec.column_name || '_SEQ" '
||' START WITH ' || to_char( curr_mx + 1 ) ||';'
);
end loop;
end;
/
此代码使用DBMS_OUTPUT,因此您可以将其假脱机到文件中供以后使用。如果您使用的是像SQL Developer这样的IDE,则可能需要启用DBMS_OUTPUT。请遵循this StackOverflow answer中的指导。
如果您可以保证所有表都有一个主键,这是一个名为ID的数字列,那么您可以简化select语句。相反,如果你的一些主键是复合约束,你将需要处理它。
显然,我生成序列是因为它们更简单。编写更复杂的触发器实现是留给读者的练习:)
答案 1 :(得分:1)
感谢脚本。我稍微修改了它并执行了触发器。随意使用它。
declare
curr_mx number;
counter number;
seq_name varchar2 (30);
trigger_name varchar2 (30);
begin
for lrec in ( select ucc.table_name
, ucc.column_name
from user_constraints uc
join user_cons_columns ucc
on ucc.table_name = uc.table_name
and ucc.constraint_name = uc.constraint_name
join user_tab_columns utc
on utc.table_name = ucc.table_name
and utc.column_name = ucc.column_name
where uc.constraint_type = 'P' -- primary key
and utc.data_type = 'NUMBER' -- only numeric columns
)
loop
execute immediate 'select (max ('|| lrec.column_name ||')+1) from ' ||lrec.table_name
into curr_mx;
IF curr_mx is null THEN
curr_mx := 0;
END IF;
IF counter is null THEN
counter := 0;
END IF;
/* check length of sequence name, 30 is max */
IF length(lrec.table_name ||'_'|| lrec.column_name || '_SEQ') > 30 THEN
IF length(lrec.column_name || '_SEQ') > 30 THEN
seq_name := counter || '_PKA_SEQ';
ELSE
seq_name := lrec.column_name || '_SEQ';
END IF;
ELSE
seq_name := lrec.table_name ||'_'|| lrec.column_name || '_SEQ';
END IF;
/* check length of trigger name, 30 is max */
IF length(lrec.table_name || '_PKA_T') > 30 THEN
trigger_name := counter || '_PKA_T';
ELSE
trigger_name := lrec.table_name || '_PKA_T';
END IF;
counter := counter +1;
dbms_output.put_line(
'CREATE SEQUENCE "' || seq_name || '"'
||' START WITH ' || to_char( curr_mx + 1 ) ||';'
);
dbms_output.put_line('/');
dbms_output.put_line(
'CREATE OR REPLACE TRIGGER "' || trigger_name || '"'
|| ' BEFORE INSERT ON "' || lrec.table_name || '"'
|| ' FOR EACH ROW '
|| ' BEGIN '
|| ' :new."' || lrec.column_name || '" := "' || seq_name || '".nextval;'
|| ' END;'
);
dbms_output.put_line('/');
end loop;
end;
我还检查了序列和触发器的名称是否超过30个字符,因为oracle不接受这些。
编辑: 不得不在每一行后加上'/',这样你就可以在一次运行中执行所有语句。