CONSTRAINT для проверки значений из таблицы, связанной с удаленностью (через соединение и т.д.).
Я хотел бы добавить ограничение, которое будет проверять значения из связанной таблицы.
У меня есть 3 таблицы:
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
);
(Если вы хотите, чтобы я установил ограничение с помощью FK, дайте мне знать.)
Я хочу добавить ограничение на somethink_usr_rel
, которое проверяет type
в role
( "две таблицы прочь" ), например:
ALTER TABLE somethink_usr_rel
ADD CONSTRAINT CH_sm_usr_type_check
CHECK (usr.role.type = 'SOME_ENUM');
Я пытался сделать это с помощью JOIN
, но не удалось. Любая идея, как его достичь?
Ответы
Ответ 1
Ограничения CHECK
настоящее время не могут ссылаться на другие таблицы. По документации:
В настоящее время выражения CHECK
не могут содержать подзапросов и ссылаться на переменные, кроме столбцов текущей строки.
Одним из способов является использование триггера, подобного продемонстрированному @Wolph.
Чистое решение без триггеров: добавьте избыточные столбцы и включите их в ограничения FOREIGN KEY, которые в любом случае являются первым выбором для обеспечения ссылочной целостности. Соответствующий ответ на dba.SE с подробными инструкциями:
Другой вариант - "подделать" функцию IMMUTABLE, выполняющую проверку, и использовать ее в ограничении CHECK
. Postgres позволит это, но помните о возможных последствиях. Вы лучше всего сделаете это NOT VALID
ограничением. Подробности:
Ответ 2
Ограничение A CHECK
не является вариантом, если вам нужны соединения. Вы можете создать триггер, который вызывает ошибку.
Посмотрите на этот пример: 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();
Ответ 3
... Я сделал это так (nazwa = имя пользователя, firma = название компании):
CREATE TABLE users
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
nazwa character varying(20),
firma character varying(50)
);
CREATE TABLE test
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
firma character varying(50),
towar character varying(20),
nazwisko character varying(20)
);
ALTER TABLE public.test ENABLE ROW LEVEL SECURITY;
CREATE OR REPLACE FUNCTION whoIAM3() RETURNS varchar(50) as $$
declare
result varchar(50);
BEGIN
select into result users.firma from users where users.nazwa = current_user;
return result;
END;
$$ LANGUAGE plpgsql;
CREATE POLICY user_policy ON public.test
USING (firma = whoIAM3());
CREATE FUNCTION test_trigger_function()
RETURNS trigger AS $$
BEGIN
NEW.firma:=whoIam3();
return NEW;
END
$$ LANGUAGE 'plpgsql'
CREATE TRIGGER test_trigger_insert BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE test_trigger_function();