简体   繁体   中英

PostgreSQL, MonetDB and MySQL add foreign key to existing table

When I add a foreign key to a table that already has data, what does each of these database management systems do?

Do they analyze each value of the column to confirm it is a value from the referenced table primary key ?

Or do they have some other optimized mechanism ? And if that's the case, what is that mechanism ?

I can't confirm for MonetDB, but in PostgreSQL and MySQL (and most probably on MonetDB too) the answer is yes, they will check every value and will raise an error if the key does not exists on the referenced table.

Notice that the referenced column doesnt need to be the primary key for the referenced table - you can reference any column as a foreign key to the other table.

Yes, of course, a constraint that is not enforced would make no sense. You can just try(this is for Postgres):


DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE one
        ( one_id SERIAL NOT NULL PRIMARY KEY
        , name varchar
        );
INSERT INTO one(name)
SELECT 'name_' || gs::text
FROM generate_series(1,10) gs ;

CREATE TABLE two
        ( two_id SERIAL NOT NULL PRIMARY KEY
        , one_id INTEGER -- REFERENCES one(one_id)
        );

INSERT INTO two(one_id)
SELECT one_id
FROM one ;

DELETE FROM one WHERE one_id%5=0;

ALTER TABLE two
        ADD FOREIGN KEY (one_id) REFERENCES one(one_id)
        ;

\d one
\d two

Result:


NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to table tmp.one
drop cascades to table tmp.two
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 10
CREATE TABLE
INSERT 0 10
DELETE 2
ERROR:  insert or update on table "two" violates foreign key constraint "two_one_id_fkey"
DETAIL:  Key (one_id)=(5) is not present in table "one".
                                  Table "tmp.one"
 Column |       Type        |                      Modifiers                       
--------+-------------------+------------------------------------------------------
 one_id | integer           | not null default nextval('one_one_id_seq'::regclass)
 name   | character varying | 
Indexes:
    "one_pkey" PRIMARY KEY, btree (one_id)

                             Table "tmp.two"
 Column |  Type   |                      Modifiers                       
--------+---------+------------------------------------------------------
 two_id | integer | not null default nextval('two_two_id_seq'::regclass)
 one_id | integer | 
Indexes:
    "two_pkey" PRIMARY KEY, btree (two_id)

The error message is the same as for an actual insert or update. And you can see that the engine bails out once it en counters the first conflicting row.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM