迁移ASE数据库的表之间存在引用时脚本执行情况
迁移ASE数据库的表结构时,需要注意表DDL的顺序,否则有些对象会因为其所引用的对象不存在而导致创建不成功。
解决的方法:将同样的脚本执行两次。
据我所知,sybase central或者ddlgen导出的语法中是没有很好的处理好对象之间的引用先后顺序的,所以,很有可能你的脚本需要执行两次才能保证所有的对象都成功创建上。
下面举个简单的例子,两张表,一张外键引用另一张。
sybase ASE中要求被外键引用的表的被引用列上有唯一约束。
在移植对象DDL的时候,举个例子:表A外键引用表B,如果导出的DLL语句中表A的定义语句在前面,而表B的DDL在后面。那么在创建表A的时候会因为外键引用的表B不存在而导致表A创建不成功。表B是能够成功创建的。
第二次执行上面相同的脚本时,首先会成功创建表A,因为其所引用的表B已经创建上了。而表B不会再次创建因为上次执行的时候已建上,会给出一个错误信息。这在isql是个错误信息,可能在sybase central中会是一个让人讨厌的弹出窗口。
总之,如果数据库内表之间定义了引用关系,那么同样的脚本语句需要执行两边才能成功完成工作。下面举一个外键引用的例子,分两种情况:
- 不带if exitsts .... drop table ...
- 带if exitsts .... drop table ...
有两种表:部门信息表dept,学生信息表students,学生表中的部门编号列引用表dept的dept_id列。正常的表定义语法如下:
use tempdb
gocreate table dept(dept_id int unique not null, dept_name varchar(100) null)
go
create table students ( id int not null,name varchar(30) null,
dept_id int not null,constraint fk_students_dept_id foreign key(dept_id) references dept(dept_id) )
go
下面的测试假设进行表结构迁移时,用工具导出的表定义语法的顺序不正确。
第一种情况:不带if exitsts .... drop table ...
执行第一遍语句
1> create table students ( id int not null,name varchar(30) null,
2> dept_id int not null,constraint fk_students_dept_id foreign key(dept_id) references dept(dept_id) )
3> go
Msg 1710, Level 16, State 3:
Server 'NMR', Line 1:
Referenced table 'dept' specified in a referential constraint declared on
'students' does not exist in the database 'tempdb'.
Msg 2761, Level 16, State 4:
Server 'NMR', Line 1:
Failed to create declarative constraints on table 'students' in database
'tempdb'.
1> create table dept(dept_id int unique not null, dept_name varchar(100) null)
2> go
因为学生信息表students没有成功创建,执行第二遍语句,
1>
2>
3>
4> use tempdb
5> go
1> create table students ( id int not null,name varchar(30) null,
2> dept_id int not null,constraint fk_students_dept_id foreign key(dept_id) references dept(dept_id) )
3> go
1> create table dept(dept_id int unique not null, dept_name varchar(100) null)
2> go
Msg 2714, Level 16, State 1:
Server 'NMR', Line 1:
There is already an object named 'dept' in the database.
第二遍执行语句的时候,报部门信息表已经存在的错误。
第二种情况:带if exitsts .... drop table ...
执行效果如下:
1> use tempdb
2> go
1> if exists(select 1 from sysobjects where type='U' and name='student')
2> drop table students
3> go
1> create table students ( id int not null,name varchar(30) null,
2> dept_id int not null,constraint fk_students_dept_id foreign key(dept_id) references dept(dept_id) )
3> go
Msg 1710, Level 16, State 3:
Server 'NMR', Line 1:
Referenced table 'dept' specified in a referential constraint declared on
'students' does not exist in the database 'tempdb'.
Msg 2761, Level 16, State 4:
Server 'NMR', Line 1:
Failed to create declarative constraints on table 'students' in database
'tempdb'.
1>
2> if exists(select 1 from sysobjects where type='U' and name='dept')
3> drop table dept
4> go
1> create table dept(dept_id int unique not null, dept_name varchar(100) null)
2> go
1>
2>
3>下面是第二遍执行同样的语句
4>
5> use tempdb
6> go
1> if exists(select 1 from sysobjects where type='U' and name='student')
2> drop table students
3> go
1> create table students ( id int not null,name varchar(30) null,
2> dept_id int not null,constraint fk_students_dept_id foreign key(dept_id) references dept(dept_id) )
3> go
1>
2> if exists(select 1 from sysobjects where type='U' and name='dept')
3> drop table dept
4> go
Msg 3712, Level 16, State 1:
Server 'NMR', Line 3:
Cannot drop table 'dept' because it still has referential integrity
constraints.
1> create table dept(dept_id int unique not null, dept_name varchar(100) null)
2> go
Msg 2714, Level 16, State 1:
Server 'NMR', Line 1:
There is already an object named 'dept' in the database.
第一遍同样students不能成功创建,第二遍dept不能删除,因为存在引用它的表students,继而也不能再次创建。
PS:如果存在表之间的引用,且表之间的顺序不正确的话,需要将脚本执行两便才能保证对象都成功创建上。