Foreign keys referring other foreign keys in PostgreSQL

前端 未结 2 1568
南笙
南笙 2021-01-24 23:56

In PostgreSQL I have a database, which I intend to make the following table declaration:

CREATE TABLE canvas_user (
    id INTEGER,
    login_id VARCHAR(50) UNIQ         


        
相关标签:
2条回答
  • 2021-01-25 00:45

    A foreign key constraint does not care whether the referenced column(s) is referencing another column itself. But the referenced column(s) must be unique. That's what the error message tells you (quite clearly).

    What you are missing is that a foreign key constraint can be based on multiple columns. This should work:

    FOREIGN KEY (num, user_id, assignment_id) REFERENCES submission
    

    Replacing:

    FOREIGN KEY (num) REFERENCES submission(num),
    FOREIGN KEY (user_id) REFERENCES submission(user_id),
    FOREIGN KEY (assignment_id) REFERENCES submission(assignment_id)

    The short form of the syntax (REFERENCES submission) is possible, because you are referencing the primary key, which is the default.

    Plus, you can simplify: make submission.num the sinlge-column primary key, drop the redundant columns user_id and assignment_id from correction and reduce the fk constraint to just (num) - as discussed in @Tim's answer.

    As long as you have the multicolumn fk constraint, consider NOT NULL constraints on each of the referencing columns (as commented by @joop). Else, one or more NULL values in the referencing columns allow to escape the fk constraint with the default MATCH SIMPLE behaviour. This may or may not be intended, typically it is not.
    Alternatively consider MATCH FULL for multicolumn fk constraints to only allow that if all referencing columns are NULL. Details:

    • MATCH FULL vs MATCH SIMPLE
    0 讨论(0)
  • 2021-01-25 00:54

    Make the foreign key from the correction table to the submission table a compound key that is unique. Also, review the design of the submission table; num is a serial type and should be the unique primary key. You can add a unique constraint to the columns num, user_id, and assignment_id

    CREATE TABLE canvas_user (
        id INTEGER,
        login_id VARCHAR(50) UNIQUE NOT NULL,
        email VARCHAR(355) UNIQUE NOT NULL,
        name_given VARCHAR(30),
        name_family VARCHAR(30),
        name_full VARCHAR(50),
        role canvas_role,
        last_login TIMESTAMP,
        PRIMARY KEY (id)
    );
    
    
    CREATE TABLE problem (
        id SERIAL,
        title VARCHAR(50),
        author VARCHAR(50),
        path TEXT,
        compiler VARCHAR(20),
        PRIMARY KEY (id)
    );
    
    
    CREATE TABLE assignment (
        id INTEGER,
        title TEXT NOT NULL,
        points_possible INTEGER NOT NULL,
        problem_id INTEGER,
        PRIMARY KEY (id),
        FOREIGN KEY (problem_id) REFERENCES problem(id)
    );
    
    
    CREATE TABLE submission (
        num SERIAL,
        user_id INTEGER,
        assignment_id INTEGER,
        timestamp TIMESTAMP,
        path TEXT,
        lti_info TEXT[],
        PRIMARY KEY(num, user_id, assignment_id),
        FOREIGN KEY (user_id) REFERENCES canvas_user(id),
        FOREIGN KEY (assignment_id) REFERENCES assignment(id)
    );
    
    
    CREATE TABLE correction (
        num INTEGER,
        user_id INTEGER,
        assignment_id INTEGER,
        timestamp TIMESTAMP,
        path TEXT,
        execution_time interval,
        PRIMARY KEY(num, user_id, assignment_id),
        FOREIGN KEY (num, user_id,assignment_id ) REFERENCES submission(num, user_id, assignment_id)
    
    );
    
    0 讨论(0)
提交回复
热议问题