问题
I need to synchronize data in two tables from different Firebird databases. Precisely, I need to update records in table Person (1st DB), using records from table Users (2nd DB). Not only "name", "email", "birthday", but ID also (!). The problem is - there are tables, that depend on Person's IDs through FOREIGN KEY Constraint.
I'm trying to do this:
- Drop Foreign Key constraints in dependent tables.
- Sync two tables (which means renewing/changing IDs in table Person)
- Change appropriate IDs in dependent tables.
- Adding Foreign Key constraints in dependent tables.
Last step causes a error (log from java application, but it's the same if I perform these steps directly in 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"
(Employee - is one of the dependent tables)
My question is, whether I can avoid this error. Or maybe there are some ideas on how to change IDs in related tables. There are probably special RDBMS tools to sync databases, but I need to sync them through Java application, therefore using only sql and java. I use Firebird 2.5.1.
Complete SQL-statements (example):
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)
Some new information: it seems like sometimes IBExpert allows me to go through these steps. Actually, it gives an error in case I changed all IDs while one of the tables were in the "DATA" mode (I suppose, it's also some kind of transaction, like CREATE VIEW
).
I also found out that removing/adding Foreign Key requires exclusive lock on the whole database at least till Firebird 2.1 (or even 2.5)
回答1:
You should create your tables so that foreign keys do have ON UPDATE CASCADE
clause - then when you update the ID
it is updated in the dependent tables as well, without any additional effort on your part. So for each table which refer to the Person
table you need to do following:
-- 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;
回答2:
Instead of renumbering primary keys, insert a new record into person
with the right primary key, then update the foreign key value of employee
and delete the old person
record.
NOTE: the part below is subjective, and more of an opinion than fact.
BTW: The need to renumber your primary key is usually an indication of a design problem. Primary keys should be meaningless outside of your database and they should normally remain stable for the lifetime of the given record. In your situation apparently the key also mean something outside of your database and is also unstable.
As indicated in the answer of ain, you could use ON UPDATE CASCADE
, but IMHO that is usually a patch for the problem, not the solution. The solution is: if you have unstable primary keys: make those unique keys and add a meaningless primary key which does not need to change.
来源:https://stackoverflow.com/questions/13629087/foreign-key-reference-target-does-not-exist