外键引用目标不存在

时间:2012-11-29 15:28:24

标签: java synchronization foreign-keys constraints firebird

我需要同步来自不同Firebird数据库的两个表中的数据。确切地说,我需要使用表Users(2nd DB)中的记录更新表Person(1st DB)中的记录。不仅是“名字”,“电子邮件”,“生日”,而且ID也是(!)。问题是 - 有表,通过FOREIGN KEY约束依赖于Person的ID。

我正在尝试这样做:

  1. 在依赖表中删除外键约束。
  2. 同步两个表(表示更新/更改表人员中的ID)
  3. 更改从属表中的相应ID。
  4. 在从属表中添加外键约束。
  5. 最后一步导致错误(从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语句(示例):

    1. ALTER TABLE employee DROP CONSTRAINT fk_employee_person
      
    2. UPDATE person SET id = 555555 WHERE id = 3000005
      
    3. UPDATE employee SET person_id = 555555 WHERE person_id = 3000005
      
    4. ALTER TABLE employee ADD CONSTRAINT fk_employee_person FOREIGN KEY (person_id) REFERENCES person(id)
      
    5. 一些新信息:似乎有时IBExpert允许我完成这些步骤。实际上,如果我在其中一个表处于“DATA”模式时更改了所有ID,则会出现错误(我想,它也是某种事务,如CREATE VIEW)。

      我还发现删除/添加外键需要对整个数据库进行独占锁定,至少要等到Firebird 2.1(甚至2.5)

2 个答案:

答案 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,但恕我直言,这通常是问题的补丁,而不是解决方案。解决方案是:如果您有不稳定的主键:创建这些唯一键并添加无意义的主键,无需更改。