0

I'm modelling a hierarchy of three entities for a therapy planning software. A therapy is basically understood as a number of medications that are given to a patient on a number of days. I want to be able to cancel therapy on any given day, in a write-only-once fashion (for quality control certification purposes).

Here's the concrete question: Is it ok to reuse a part of a composite foreign key as a another foreign key? In my case the composite key points from the medication table to the day table, which then points back to the therapy. The therapy id is included in the composite foreign key in the medication table, so I could use this as a foreign key, making querying more easy?

The table definitions should be something like this (modulo hickups in my raw SQL skills, I usually always employ some kind of ORM):

CREATE TABLE therapy (
    "id" INTEGER NOT NULL,
    "start" DATE NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE day (
    "therapy_id" INTEGER NOT NULL,
    "day" INTEGER NOT NULL,
    "revision" INTEGER NOT NULL,
    "comment" TEXT;
    "cancelled" BOOLEAN NOT NULL;
    PRIMARY KEY (therapy_id, day, revision),
FOREIGN KEY(therapy_id) REFERENCES therapy (id)
);

CREATE TABLE medication (
    "id" INTEGER NOT NULL,
    "therapy_id" INTEGER NOT NULL,
    "day" INTEGER NOT NULL,
    "revision" INTEGER NOT NULL,
    "substance" VARCHAR(100) NOT NULL,
    "dosage" VARCHAR(50) NOT NULL,
    PRIMARY KEY (id),
FOREIGN KEY(therapy_id, day, revision) REFERENCES day (therapy_id, day, revision),
-- wondering if this is ok
    FOREIGN KEY(therapy_id) REFERENCES therapy (id)
);

Please note that the relation from day to medication is one-to-many, e.g. on day 3 I want to plaster the patient with a deadly mix of Ibuprofen, Paracetamol, Aspirin, ground up coffee beans and a good shot of Jaegermeister.

room2web
  • 1,179
  • 1
  • 8
  • 14

1 Answers1

1

Here's what you started with.

CREATE TABLE medication (
    "id" INTEGER NOT NULL,               -- You don't need this.
    "therapy_id" INTEGER NOT NULL,
    "day" INTEGER NOT NULL,
    "revision" INTEGER NOT NULL,
    "substance" VARCHAR(100),
    "dosage" VARCHAR(50),
    PRIMARY KEY (id),                    -- Drop this.
    FOREIGN KEY(therapy_id, day, revision) 
        REFERENCES day (therapy_id, day, revision),  -- Ok, but should be PK.
    FOREIGN KEY(therapy_id) REFERENCES therapy (id) -- You don't need this.
);

The column "id" serves no useful purpose, and has instead convinced you that you don't need a unique constraint on the real key: {therapy_id, day, revision}. Replace the useless primary key constraint on "id" with a primary key constraint on {therapy_id, day, revision}. Drop the last foreign key constraint. You know "therapy_id" will reference an existing row, because the foreign key constraint in the table "day" requires it.

That leaves us with this.

CREATE TABLE medication (
    "therapy_id" INTEGER NOT NULL,
    "day" INTEGER NOT NULL,
    "revision" INTEGER NOT NULL,
    "substance" VARCHAR(100),
    "dosage" VARCHAR(50),
    PRIMARY KEY (therapy_id, day, revision),
    FOREIGN KEY(therapy_id, day, revision) 
        REFERENCES day (therapy_id, day, revision)
);

It troubles me that "substance" and "dosage" are nullable. Think about that a little.

Mike Sherrill 'Cat Recall'
  • 91,602
  • 17
  • 122
  • 185
  • I made the columns in question not nullable. I don't see that (therapy_id, day, revision) constitutes a primary key, as I can have multiple medication entries for one day. But you're right, I don't need the Foreign Key constraint on medication to therapy, as this will be "inherited" from the foreign key constraint on medication to day. Performance-wise I'm still free to create an Index on therapy_id that should give me what I want. – room2web Jul 25 '13 at 15:09
  • Then you need to add another column--not an ID number--to make a real key. Perhaps a timestamp, showing when the medication was given? No way for me to tell from what you've posted. – Mike Sherrill 'Cat Recall' Jul 25 '13 at 15:12
  • I could consider substance to constitute a natural key together with (therapy_id, day, revision). But that would lead to the task of having to make sure that the physician doesn't prescribe the same medication twice a day, which in theory might be reasonable, but actually we have seen the use case that a physician enters redunant prescription into the system and has good reasons for doing that. Imposing a non-natural primary key on the table seems to be the easiest, even though not the most text-book, way out of that situation. – room2web Jul 25 '13 at 15:19