When are circular references acceptable in database?
Theoretical and practical, any help is appreciated.
One of the latest additions to the Oracle hierarchical query syntax - the NOCYCLE
keyword - was made for expressly this purpose - to deal with circular references in the data. I don't see anything wrong with it, and have had to deal with this kind of model before. It's not too difficult, especially in Oracle which supports deferrable constraints.
I guess it isn't a problem if you are using a write only database. If you plan on using the RUD part of CRUD, you'll likely run into (usually avoidable) complex issues in dealing with them.
Circular references should be avoided like the plague. It is possible to set up two way relationships, or even relationships to yourself (if you were a table that is), but a circular dependency is just asking for trouble.
rarely i run across a 1:1 relationship that is necessary and imposes a circular relationship
note that the foreign-key fields in such a relationship must be nullable, otherwise you can never delete rows from the tables
Consider cities and states. Each city exists within a state. Each state has a capital city.
CREATE TABLE city (
city VARCHAR(32),
state VARCHAR(32) NOT NULL,
PRIMARY KEY (city),
FOREIGN KEY (state) REFERENCES state (state)
);
CREATE TABLE state (
state VARCHAR(32),
capital_city VARCHAR(32),
PRIMARY KEY (state),
FOREIGN KEY (capital_city) REFERENCES city (city)
);
First problem - You cannot create these tables as shown, because a foreign key can't reference a column in a table that doesn't (yet) exist. The solution is to create them without the foreign keys, and then add the foreign keys afterwards.
Second problem - you cannot insert rows into either table, as each insert will require a pre-existing row in the other table. The solution is to set one of the foreign key columns to be NULL, and insert that data in two phases. e.g.
--Create state record
INSERT INTO state (state, capital_city) VALUES ('Florida', NULL);
--Create various city records
INSERT INTO city (city, state) VALUES ('Miami', 'Florida');
INSERT INTO city (city, state) VALUES ('Tallahassee', 'Florida');
INSERT INTO city (city, state) VALUES ('Orlando', 'Florida');
--Set one of the cities as the capital
UPDATE state SET capital_city = 'Tallahassee' WHERE state = 'Florida';
I have seen circular references done for performance reasons. It looks ugly though, and the performance might be negligible.
Example: some bulletin boards (I think phpBB does this) have a lastpostid in the category table that is a shortcut to the last post in the thread.
This creates a circle, where the last post has a FK to the category table and the category table has a FK back to the last post.
Like I said, I don't really like it, but I've seen it done.