9

I have a "comments" table that models a conversation on a topic, like this:

id serial  
topic_id integer  
parent_comment_id integer
body text

So, every comment has a reference to its topic AND eventually its parent comment (if it's not the first comment on the topic).
I'd like to add a constraint that would prevent adding rows having mismatched topic/parent (for example by referencing a topic that doesn't have the required comment, or conversely a comment that references the wrong topic).
Is this possible? Is a trigger required?

(For the record, I tried

ALTER TABLE comments ADD FOREIGN KEY (parent_comment_id, topic_id)
                 REFERENCES comments (id, topic_id)

but it complains that there is no unique constraint matching given keys for referenced table "comments")

Joril
  • 441
  • 1
  • 5
  • 10

2 Answers2

5

You need to add super-key (unique index/constraint) on both (id,topic_id). This gives you the "target" uniqueness to create your foreign key. This acts like a CHECK constraint in this case.

ALTER TABLE comments ADD 
    FOREIGN KEY (parent_comment_id, topic_id) REFERENCES comments (id, topic_id)

Note: id remains as primary key to preserve the model. Even if id is serial, it's would be wrong from a modelling perspective to change the PK to (id,topic_id)

gbn
  • 69,809
  • 8
  • 163
  • 243
  • 1
    That is technically correct, but logically this is no new constraint. Given the primary key on id, it is always fulfilled. I.e. it is just a disabilities of the implementation of the DBMS. – bernd_k Mar 16 '11 at 11:27
  • @bernd_k: this is why I said "super key". It also decouples actual PK from the superkey/FK. – gbn Mar 16 '11 at 11:45
1

Try

ALTER TABLE comments ADD FOREIGN KEY (parent_comment_id, topic_id)
    REFERENCES comments (id)

If you want this to work:

ALTER TABLE comments ADD FOREIGN KEY (parent_comment_id, topic_id)
    REFERENCES comments (id, topic_id)

Then I believe you need to change your PK to be on both the id and topic_id columns.

Also, I think this link helps explain what you need: http://www.postgresql.org/docs/8.1/static/ddl-constraints.html

SQLRockstar
  • 6,359
  • 26
  • 48
  • 1
    The first command gives me number of referencing and referenced columns for foreign key disagree :/ I think the problem with my command is that there could be multiple rows with matching parent + topic – Joril Mar 15 '11 at 22:35
  • OK, can you alter the primary key to have two columns? then your original command should work, i believe. – SQLRockstar Mar 15 '11 at 22:57