14

Tôi muốn thêm một ràng buộc sẽ kiểm tra các giá trị từ bảng có liên quan.CONSTRAINT để kiểm tra các giá trị từ một bảng có liên quan từ xa (qua tham gia, v.v.)

Tôi có 3 bảng:

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 
); 

(Nếu bạn muốn tôi để đặt hạn chế với FK cho tôi biết.)

Tôi muốn thêm một hạn chế để somethink_usr_rel để kiểm tra type trong role (" hai bảng đi "), ví dụ:

ALTER TABLE somethink_usr_rel 
    ADD CONSTRAINT CH_sm_usr_type_check 
    CHECK (usr.role.type = 'SOME_ENUM'); 

tôi cố gắng để làm điều này với JOIN s nhưng đã không thành công. Bất kỳ ý tưởng làm thế nào để đạt được nó?

Trả lời

16

CHECK hạn chế hiện không có thể tham khảo các bảng khác. Per documentation:

Hiện nay, CHECK biểu thức không thể chứa các truy vấn con cũng không đề cập đến biến khác ngoài cột của hàng hiện tại.

Một cách là sử dụng trình kích hoạt như demonstrated by @Wolph.

Giải pháp sạch sẽ không có trình kích hoạt (mạnh mẽ hơn để thực thi tính toàn vẹn tham chiếu) sẽ thêm các cột dư thừa và bao gồm chúng trong các ràng buộc FK. Hãy xem xét câu trả lời này liên quan chặt chẽ trên dba.SE với hướng dẫn chi tiết:

Một lựa chọn khác sẽ được "giả" một chức năng bất biến làm việc kiểm tra và sử dụng trong một hạn chế CHECK. Postgres sẽ cho phép điều này, nhưng phải nhận thức được những hậu quả có thể xảy ra. Bạn tốt nhất làm cho một ràng buộc NOT VALID. Thông tin chi tiết:

7

A CHECK ràng buộc không phải là một tùy chọn nếu bạn cần tham gia. Thay vào đó, bạn có thể tạo trình kích hoạt gây ra lỗi.

Hãy nhìn vào ví dụ này: 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(); 
0

... tôi đã làm nó như vậy (nazwa = user name, firma = tên công ty):

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(); 
Các vấn đề liên quan