我需要同步来自不同Firebird数据库的两个表中的数据。确切地说,我需要使用表Users(2nd DB)中的记录更新表Person(1st DB)中的记录。不仅是“名字”,“电子邮件”,“生日”,而且ID也是(!)。问题是 - 有表,通过FOREIGN KEY约束依赖于Person的ID。
我正在尝试这样做:
最后一步导致错误(从java应用程序登录,但如果我直接在IBExpert中执行这些步骤则相同):
com.bssys.db.jdbc.DBSQLException: GDS Exception. 335544466. violation of FOREIGN KEY constraint "FK_EMPLOYEE_PERSON" on table "EMPLOYEE"
Foreign key reference target does not exist, error code: HY000
Reason: violation of FOREIGN KEY constraint "FK_EMPLOYEE_PERSON" on table "EMPLOYEE"
(员工 - 是其中一个依赖表)
我的问题是,我能否避免这个错误。或者也许有一些关于如何更改相关表中的ID的想法。可能有特殊的RDBMS工具来同步数据库,但我需要通过Java应用程序同步它们,因此只使用sql和java。我使用的是Firebird 2.5.1。
完整的SQL语句(示例):
ALTER TABLE employee DROP CONSTRAINT fk_employee_person
UPDATE person SET id = 555555 WHERE id = 3000005
UPDATE employee SET person_id = 555555 WHERE person_id = 3000005
ALTER TABLE employee ADD CONSTRAINT fk_employee_person FOREIGN KEY (person_id) REFERENCES person(id)
一些新信息:似乎有时IBExpert允许我完成这些步骤。实际上,如果我在其中一个表处于“DATA”模式时更改了所有ID,则会出现错误(我想,它也是某种事务,如CREATE VIEW
)。
我还发现删除/添加外键需要对整个数据库进行独占锁定,至少要等到Firebird 2.1(甚至2.5)
答案 0 :(得分:3)
您应该创建表,以便外键具有ON UPDATE CASCADE
子句 - 然后当您更新ID
时,它也会在从属表中更新,而您无需任何额外的工作。因此,对于每个引用Person
表的表,您需要执行以下操作:
-- delete the original FK constraint
ALTER TABLE _table_ DROP CONSTRAINT _fk_constraint_name_;
-- (re)add the FK constraint with ON UPDATE CASCADE
ALTER TABLE _table_ ADD CONSTRAINT _fk_constraint_name_ FOREIGN KEY (person_id) REFERENCES person(id) ON UPDATE CASCADE;
答案 1 :(得分:1)
不是重新编号主键,而是使用正确的主键将新记录插入person
,然后更新employee
的外键值并删除旧的person
记录。
注意:以下部分是主观的,更多的是意见而不是事实。
BTW:重新编号主键的需要通常表明存在设计问题。主键在数据库之外应该没有意义,它们通常应该在给定记录的生命周期内保持稳定。在您的情况下,显然该密钥也意味着数据库之外的东西,并且也不稳定。
正如 ain 的回答所示,你可以使用ON UPDATE CASCADE
,但恕我直言,这通常是问题的补丁,而不是解决方案。解决方案是:如果您有不稳定的主键:创建这些唯一键并添加无意义的主键,无需更改。