2017-04-13 88 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

相关问题