views:

261

answers:

6

My database designs have previously been rather linear, so I'm getting stumped on what is probably a very easy to solve problem.

I have a table of "POSTS", which contain posts which may be a child of either a "CATEGORY" or a "TOPIC". What would be the best way to define the foreign key(s) for the "POSTS" table?

I suppose I could have a column named POST_CATEGORY_ID and a field named "POST_TOPIC_ID, which could be nullable, but this just doesn't sound right. Surely there is a simple solution that I'm missing!

+1  A: 

I think a foreign key declaration can only refer to a single table:

FOREIGN KEY(CATEGORY_ID) REFERENCES CATEGORY(CATEGORY_ID);
FOREIGN KEY(TOPIC_ID) REFERENCES TOPIC(TOPIC_ID);

If I'm correct, you'll have to have two foreign keys, one for the CATEGORY table and another for TOPIC, and both need to be nullable.

duffymo
+4  A: 

You're on the right track with nullable POST_CATEGORY_ID and POST_TOPIC_ID fields. This will model that a post optionally be related to a category and optionally related to a topic.

If this is meant to be exclusive and mandatory, you will need to add a check constraint that either is null, but not both.

camh
The thing that bothers me about this is what if something else later on contains POSTS? I'd have to modify the table to support another nullable column that references the new table. I'm not immune to doing that, it just seems to be off somehow.
A: 

The best way is to use Inheritance. You will have two specializations of "Posts": "Posts_Category" and "Posts_Topic" Both have "post_id" (which relates to the parent table "Posts") and another field:

"Category_ID" ("Posts_Category")

"Topic_ID" ("Posts_Topic")

If this sounds confuse look at Doctrine (PHP ORM) at their documentation: http://www.doctrine-project.org/documentation/manual/1_0/en/inheritance

A: 

If you want to define foreign keys in the database, the solution that you're suggesting sounds right. I also suggest writing some code in a trigger to make sure that both fields aren't null.

Linda
+1  A: 

How about having the categories and topics in the same table

create table topics_categories( id number, description varchar2(100), item_type char(1)); --C or T

Then a single foreign key to topics_categories

Tony BenBrahim
+2  A: 

You could do many-to-many relationships between POST and CATEGORY and POST and TOPIC:

POST
----
ID
Text ...
...

CATEGORY
--------
ID
Name

TOPIC
-----
ID
Name

POST_CATEGORY
-------------
POST_ID (FK)
CATEGORY_ID (FK)

POST_TOPIC
----------
POST_ID (FK)
TOPIC_ID (FK)

This way, a post can be associated with any number of categories and topics.

Andy White
This sounds more extensible - at least from an intermediary table perspective, but wouldn't this just be taking just my nullable columns out of the POSTS table and creating a new table out of them?
I think you won't need any nullables if you do this. You only insert a record in the many-to-many table if the relationship exists
Andy White
Wait a minute - I think I follow now. So, in the future, let's say I have a new table called BOOKS that require child POSTS, I just add a table called POST_BOOK with foreign keys to POSTS and BOOKS?
Yeah, in this way, you can add as many relationships as you want without touching the existing tables. One thing to be careful with though is the many-to-many relationship. You might not always want the many-to-many relationship. (e.g. a POST might only have one CATEGORY, rather than many)
Andy White
(continued)... You can address this in the way you write the code, or you can set unique constraints on the appropriate columns of the many-to-many table, so that a post can only have one category, etc.
Andy White
Thanks a million. Now that I see it, it makes perfect sense. I can definately see where this ia a lot better than my initial thinking.
One problem with this approach is that it becomes more difficult to have a constraint that ensures a post belongs only to a topic or category and not both. The constraint has to reference the other tables and then impacts extensibility.
camh
Yeah, I agree. I was thinking he might not really care about constraining it so strictly though. For blog engines, I think extensibility is usually more important than being really strict in the DB.
Andy White