2017-04-13 86 views
0

我是新與PostgreSQL和我想創建3個表:PostgreSQL的 - 至少一個需求

Students(id, name) 
Courses(num, name) 
and Register(id, num) 

CREATE TABLE Students (sid integer, name text,PRIMARY KEY (sid)) 
CREATE TABLE Courses(num integer,name text, PRIMARY KEY (num)) 
CREATE TABLE Register(sid integer, num integer, FOREGIN KEY (sid, num) REFERENCES (Students, Register)) 

我想強制每個學生註冊到至少一門課程的需求,如何我可以在不改變上述表格的屬性的情況下做到嗎? TNX

+0

您可以創建一個'CHECK'約束,但它必須推遲,你將不得不使用交易。延遲約束在插入/更新時不檢查,而是在提交時檢查。一旦進入交易,您也可以更改模式。通過屬性https://www.postgresql.org/docs/current/static/sql-set-constraints.html – coladict

+0

- 你指的是列? –

+0

@VaoTsun是的,我不想改變架構。 – cbdes

回答

0

您不能使用任何類型的CONSTRAINT,因爲所有的人都可以參照只有一個表(除了FOREIGN KEY,但存在純粹是爲了保持參照完整性)。

「強制執行」你的邏輯的唯一方法是編寫觸發器。在PostgreSQL中,您也可以編寫CONSTRAINT TRIGGERS, which can be DEFERRED以允許在提交事務後執行檢查。這是非常重要的,因爲如果您在沒有延期支票的情況下編寫觸發器,它將阻止任何新學生被插入(因爲在插入時,學生還沒有任何註冊課程)。

CREATE FUNCTION check_student_registers() 
    RETURNS trigger 
    LANGUAGE plpgsql 
AS $func$ 
BEGIN 
    IF NOT EXISTS(SELECT 1 FROM Register WHERE sid = CASE TG_OP WHEN 'INSERT' THEN NEW.sid ELSE OLD.sid END) THEN 
    RAISE EXCEPTION 'Some students did not registered to any courses'; 
    END IF; 
    RETURN NULL; 
END 
$func$; 

CREATE CONSTRAINT TRIGGER trg_check_student_registers 
    AFTER INSERT ON Students 
    DEFERRABLE INITIALLY DEFERRED 
    FOR EACH ROW 
    EXECUTE PROCEDURE check_student_registers(); 

CREATE CONSTRAINT TRIGGER trg_check_student_registers 
    AFTER UPDATE OF sid OR DELETE ON Register 
    DEFERRABLE INITIALLY DEFERRED 
    FOR EACH ROW 
    EXECUTE PROCEDURE check_student_registers(); 

觸發可以暫時不過關斷,所以這些類型的邏輯的可能有點「小的」強制執行比傳統CONSTRAINT秒。

http://rextester.com/EXPW54612

相關問題