In an existing schema I am introducing audit trail/milestone support only for one of the tables. For discussing the question we'll use following simplified toy example for better illustration of a question.
DEPARTMENT
ID | NAME | CREATED_TS | MODIFIED_TS | VERSION
1 | "ABC" | 11/20/2015 | 12/1/9999 | 1
Now when every time update request for department
record for id=1 comes in, system does following. Basically each update is an INSERT
- which changes existing record's MODIFIED_TS
to the time UPDATE
request came in and latest record's MODIFIED_TS
always remains as 12/1/9999
(aka INFINITY
TIMESTAMP)
Say updating ID=1 record where name was changed , following is what it looks like in db.
DEPARTMENT
ID | NAME | CREATED_TS | MODIFIED_TS | VERSION
1 | "ABC" | 11/20/2015 | 11/22/2015 | 1
1 | "XYZ" | 11/22/2015 | 12/1/9999 | 2
Now assume there is an existing EMPLOYEE
table with DEPT_ID
as a foreign key. Note that EMPLOYEE
table doesn't have an audit trail requirement so there is no INFINITY
timestamp or VERSION
ing concept there. EMPLOYEE
table looks like as below
EMPLOYEE
ID | NAME | AGE | DEPT_ID
1 | "John" | 31 | 1
Everything was fine in terms of EMPLOYEE having a FK relationship with DEPT where DEPT had ID as a PK before. Now DEPARTMENT
table's PK is changed to a composite PK (ID,VERSION)
After these schema changes for DEPARTMENT
table to create auit trail for its data, FK in EMPLOYEE
will have to somehow create a FK in such a way where not only DEPT_ID
but also include INFINITY
timestamp ( MODIFIED_TS
) of DEPT
record into it because EMPLOYEE
will always be referring the latest DEPT
record (requirement)
What's the best way to change EMPLOYEE
table's FK for pointing to the most current record in DEPT
table?
This is a terrible data-modelling hack to solve your problem; don't try this at home...
Since the PK for department is {id, modified_ts}, the FK from employee must also be composite (or it could point to another unique set of columns). So the solution is to give it what it wants: a column with a constant value of 'infinity'. ('infinity' is a valid value for dates and timestamps in postgres, you don't need to invent your own sentinel values)
CREATE TABLE department
( id INTEGER NOT NULL
, name varchar
, created_ts timestamp
, modified_ts timestamp
, version integer not null default 0
, PRIMARY KEY (id, modified_ts)
);
INSERT INTO department (id, name, created_ts, modified_ts, version) VALUES
(1 , 'ABC', '2015-11-20' , '2015-11-22' , 1) ,
(1 , 'XYZ', '2015-11-22' , 'infinity' , 2) ;
-- CREATE UNIQUE INDEX ON department (id) WHERE modified_ts = 'infinity'::timestamp;
-- Now assume there is an existing EMPLOYEE table with DEPT_ID as a foreign key. Note that EMPLOYEE table doesn't have an audit trail requirement so there is no INFINITY timestamp or VERSIONing concept there. EMPLOYEE table looks like as below
CREATE TABLE employee
( id INTEGER NOT NULL PRIMARY KEY
, name varchar
, age integer not null default 0
, modified_ts timestamp NOT NULL DEFAULT 'infinity'::timestamp CHECK (modified_ts = 'infinity'::timestamp)
, dept_id INTEGER NOT NULL
, FOREIGN KEY (id,modified_ts)
REFERENCES department(id, modified_ts)
);
INSERT INTO employee(id ,name,age,dept_id) VALUES
(1 , 'John' , 31 , 1);
DEFERRABLE INITIALLY DEFERRED
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.