I would like to add a constraint that will check values from related table.
I have 3 tables:
CREATE TABLE somethink_usr_rel ( user_id BIGINT NOT NULL, stomethink_id BIGINT NOT NULL ); CREATE TABLE usr ( id BIGINT NOT NULL, role_id BIGINT NOT NULL ); CREATE TABLE role ( id BIGINT NOT NULL, type BIGINT NOT NULL );
(If you want me to put constraint with FK let me know.)
I want to add a constraint to somethink_usr_rel
that checks type
in role
("two tables away"), e.g.:
ALTER TABLE somethink_usr_rel ADD CONSTRAINT CH_sm_usr_type_check CHECK (usr.role.type = 'SOME_ENUM');
I tried to do this with JOIN
s but didn't succeed. Any idea how to achieve it?
CHECK
constraints cannot currently reference other tables. The manual:
Currently,
CHECK
expressions cannot contain subqueries nor refer to variables other than columns of the current row.
One way is to use a trigger like demonstrated by @Wolph.
A clean solution without triggers: add redundant columns and include them in FOREIGN KEY
constraints, which are the first choice to enforce referential integrity. Related answer on dba.SE with detailed instructions:
Another option would be to "fake" an IMMUTABLE
function doing the check and use that in a CHECK
constraint. Postgres will allow this, but be aware of possible caveats. Best make that a NOT VALID
constraint. See:
A CHECK
constraint is not an option if you need joins. You can create a trigger which raises an error instead.
Have a look at this example: http://www.postgresql.org/docs/9.1/static/plpgsql-trigger.html#PLPGSQL-TRIGGER-EXAMPLE
CREATE TABLE emp ( empname text, salary integer, last_date timestamp, last_user text ); CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$ BEGIN -- Check that empname and salary are given IF NEW.empname IS NULL THEN RAISE EXCEPTION 'empname cannot be null'; END IF; IF NEW.salary IS NULL THEN RAISE EXCEPTION '% cannot have null salary', NEW.empname; END IF; -- Who works for us when she must pay for it? IF NEW.salary < 0 THEN RAISE EXCEPTION '% cannot have a negative salary', NEW.empname; END IF; -- Remember who changed the payroll when NEW.last_date := current_timestamp; NEW.last_user := current_user; RETURN NEW; END; $emp_stamp$ LANGUAGE plpgsql; CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With