foreign_key.sql
来自「postgresql8.3.4源码,开源数据库」· SQL 代码 · 共 924 行 · 第 1/2 页
SQL
924 行
-- not an implicit coercion (or use numeric=numeric, but that's not part-- of the integer opfamily)CREATE TABLE FKTABLE (ftest1 numeric REFERENCES pktable);DROP TABLE PKTABLE;-- On the other hand, this should work because int implicitly promotes to-- numeric, and we allow promotion on the FK sideCREATE TABLE PKTABLE (ptest1 numeric PRIMARY KEY);INSERT INTO PKTABLE VALUES(42);CREATE TABLE FKTABLE (ftest1 int REFERENCES pktable);-- Check it actually worksINSERT INTO FKTABLE VALUES(42); -- should succeedINSERT INTO FKTABLE VALUES(43); -- should failUPDATE FKTABLE SET ftest1 = ftest1; -- should succeedUPDATE FKTABLE SET ftest1 = ftest1 + 1; -- should failDROP TABLE FKTABLE;DROP TABLE PKTABLE;-- Two columns, two tablesCREATE TABLE PKTABLE (ptest1 int, ptest2 inet, PRIMARY KEY(ptest1, ptest2));-- This should fail, because we just chose really odd typesCREATE TABLE FKTABLE (ftest1 cidr, ftest2 timestamp, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable);-- Again, so should this...CREATE TABLE FKTABLE (ftest1 cidr, ftest2 timestamp, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));-- This fails because we mixed up the column orderingCREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);-- As does this...CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));-- And again..CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));-- This works...CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));DROP TABLE FKTABLE;-- As does thisCREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));DROP TABLE FKTABLE;DROP TABLE PKTABLE;-- Two columns, same table-- Make sure this still works...CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,ptest4) REFERENCES pktable(ptest1, ptest2));DROP TABLE PKTABLE;-- And this, CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,ptest4) REFERENCES pktable);DROP TABLE PKTABLE;-- This shouldn't (mixed up columns)CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,ptest4) REFERENCES pktable(ptest2, ptest1));-- Nor should this... (same reason, we have 4,3 referencing 1,2 which mismatches typesCREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,ptest3) REFERENCES pktable(ptest1, ptest2));-- Not this one either... Same as the last one except we didn't defined the columns being referenced.CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,ptest3) REFERENCES pktable);---- Now some cases with inheritance-- Basic 2 table case: 1 column of matching types.create table pktable_base (base1 int not null);create table pktable (ptest1 int, primary key(base1), unique(base1, ptest1)) inherits (pktable_base);create table fktable (ftest1 int references pktable(base1));-- now some ins, upd, delinsert into pktable(base1) values (1);insert into pktable(base1) values (2);-- let's insert a non-existant fktable valueinsert into fktable(ftest1) values (3);-- let's make a valid row for thatinsert into pktable(base1) values (3);insert into fktable(ftest1) values (3);-- let's try removing a row that should fail from pktabledelete from pktable where base1>2;-- okay, let's try updating all of the base1 values to *4-- which should fail.update pktable set base1=base1*4;-- okay, let's try an update that should work.update pktable set base1=base1*4 where base1<3;-- and a delete that should workdelete from pktable where base1>3;-- cleanupdrop table fktable;delete from pktable;-- Now 2 columns 2 tables, matching typescreate table fktable (ftest1 int, ftest2 int, foreign key(ftest1, ftest2) references pktable(base1, ptest1));-- now some ins, upd, delinsert into pktable(base1, ptest1) values (1, 1);insert into pktable(base1, ptest1) values (2, 2);-- let's insert a non-existant fktable valueinsert into fktable(ftest1, ftest2) values (3, 1);-- let's make a valid row for thatinsert into pktable(base1,ptest1) values (3, 1);insert into fktable(ftest1, ftest2) values (3, 1);-- let's try removing a row that should fail from pktabledelete from pktable where base1>2;-- okay, let's try updating all of the base1 values to *4-- which should fail.update pktable set base1=base1*4;-- okay, let's try an update that should work.update pktable set base1=base1*4 where base1<3;-- and a delete that should workdelete from pktable where base1>3;-- cleanupdrop table fktable;drop table pktable;drop table pktable_base;-- Now we'll do one all in 1 table with 2 columns of matching typescreate table pktable_base(base1 int not null, base2 int);create table pktable(ptest1 int, ptest2 int, primary key(base1, ptest1), foreign key(base2, ptest2) references pktable(base1, ptest1)) inherits (pktable_base);insert into pktable (base1, ptest1, base2, ptest2) values (1, 1, 1, 1);insert into pktable (base1, ptest1, base2, ptest2) values (2, 1, 1, 1);insert into pktable (base1, ptest1, base2, ptest2) values (2, 2, 2, 1);insert into pktable (base1, ptest1, base2, ptest2) values (1, 3, 2, 2);-- fails (3,2) isn't in base1, ptest1insert into pktable (base1, ptest1, base2, ptest2) values (2, 3, 3, 2);-- fails (2,2) is being referenceddelete from pktable where base1=2;-- fails (1,1) is being referenced (twice)update pktable set base1=3 where base1=1;-- this sequence of two deletes will work, since after the first there will be no (2,*) referencesdelete from pktable where base2=2;delete from pktable where base1=2;drop table pktable;drop table pktable_base;-- 2 columns (2 tables), mismatched typescreate table pktable_base(base1 int not null);create table pktable(ptest1 inet, primary key(base1, ptest1)) inherits (pktable_base);-- just generally bad types (with and without column references on the referenced table)create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable);create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable(base1, ptest1));-- let's mix up which columns reference whichcreate table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable);create table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable(base1, ptest1));create table fktable(ftest1 int, ftest2 inet, foreign key(ftest1, ftest2) references pktable(ptest1, base1));drop table pktable;drop table pktable_base;-- 2 columns (1 table), mismatched typescreate table pktable_base(base1 int not null, base2 int);create table pktable(ptest1 inet, ptest2 inet[], primary key(base1, ptest1), foreign key(base2, ptest2) references pktable(base1, ptest1)) inherits (pktable_base);create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(base2, ptest2) references pktable(ptest1, base1)) inherits (pktable_base);create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references pktable(base1, ptest1)) inherits (pktable_base);create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references pktable(base1, ptest1)) inherits (pktable_base);drop table pktable;drop table pktable_base;---- Deferrable constraints-- (right now, only FOREIGN KEY constraints can be deferred)---- deferrable, explicitly deferredCREATE TABLE pktable ( id INT4 PRIMARY KEY, other INT4);CREATE TABLE fktable ( id INT4 PRIMARY KEY, fk INT4 REFERENCES pktable DEFERRABLE);-- default to immediate: should failINSERT INTO fktable VALUES (5, 10);-- explicitly defer the constraintBEGIN;SET CONSTRAINTS ALL DEFERRED;INSERT INTO fktable VALUES (10, 15);INSERT INTO pktable VALUES (15, 0); -- make the FK insert validCOMMIT;DROP TABLE fktable, pktable;-- deferrable, initially deferredCREATE TABLE pktable ( id INT4 PRIMARY KEY, other INT4);CREATE TABLE fktable ( id INT4 PRIMARY KEY, fk INT4 REFERENCES pktable DEFERRABLE INITIALLY DEFERRED);-- default to deferred, should succeedBEGIN;INSERT INTO fktable VALUES (100, 200);INSERT INTO pktable VALUES (200, 500); -- make the FK insert validCOMMIT;-- default to deferred, explicitly make immediateBEGIN;SET CONSTRAINTS ALL IMMEDIATE;-- should failINSERT INTO fktable VALUES (500, 1000);COMMIT;DROP TABLE fktable, pktable;-- tricky behavior: according to SQL99, if a deferred constraint is set-- to 'immediate' mode, it should be checked for validity *immediately*,-- not when the current transaction commits (i.e. the mode change applies-- retroactively)CREATE TABLE pktable ( id INT4 PRIMARY KEY, other INT4);CREATE TABLE fktable ( id INT4 PRIMARY KEY, fk INT4 REFERENCES pktable DEFERRABLE);BEGIN;SET CONSTRAINTS ALL DEFERRED;-- should succeed, for nowINSERT INTO fktable VALUES (1000, 2000);-- should cause transaction abort, due to preceding errorSET CONSTRAINTS ALL IMMEDIATE;INSERT INTO pktable VALUES (2000, 3); -- too lateCOMMIT;DROP TABLE fktable, pktable;-- deferrable, initially deferredCREATE TABLE pktable ( id INT4 PRIMARY KEY, other INT4);CREATE TABLE fktable ( id INT4 PRIMARY KEY, fk INT4 REFERENCES pktable DEFERRABLE INITIALLY DEFERRED);BEGIN;-- no error hereINSERT INTO fktable VALUES (100, 200);-- error here on commitCOMMIT;DROP TABLE pktable, fktable CASCADE;-- test notice about expensive referential integrity checks,-- where the index cannot be used because of type incompatibilities.CREATE TEMP TABLE pktable ( id1 INT4 PRIMARY KEY, id2 VARCHAR(4) UNIQUE, id3 REAL UNIQUE, UNIQUE(id1, id2, id3));CREATE TEMP TABLE fktable ( x1 INT4 REFERENCES pktable(id1), x2 VARCHAR(4) REFERENCES pktable(id2), x3 REAL REFERENCES pktable(id3), x4 TEXT, x5 INT2);-- check individual constraints with alter table.-- should fail-- varchar does not promote to realALTER TABLE fktable ADD CONSTRAINT fk_2_3FOREIGN KEY (x2) REFERENCES pktable(id3);-- nor to int4ALTER TABLE fktable ADD CONSTRAINT fk_2_1FOREIGN KEY (x2) REFERENCES pktable(id1);-- real does not promote to int4ALTER TABLE fktable ADD CONSTRAINT fk_3_1FOREIGN KEY (x3) REFERENCES pktable(id1);-- int4 does not promote to textALTER TABLE fktable ADD CONSTRAINT fk_1_2FOREIGN KEY (x1) REFERENCES pktable(id2);-- should succeed-- int4 promotes to realALTER TABLE fktable ADD CONSTRAINT fk_1_3FOREIGN KEY (x1) REFERENCES pktable(id3);-- text is compatible with varcharALTER TABLE fktable ADD CONSTRAINT fk_4_2FOREIGN KEY (x4) REFERENCES pktable(id2);-- int2 is part of integer opfamily as of 8.0ALTER TABLE fktable ADD CONSTRAINT fk_5_1FOREIGN KEY (x5) REFERENCES pktable(id1);-- check multikey cases, especially out-of-order column lists-- these should workALTER TABLE fktable ADD CONSTRAINT fk_123_123FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id1,id2,id3);ALTER TABLE fktable ADD CONSTRAINT fk_213_213FOREIGN KEY (x2,x1,x3) REFERENCES pktable(id2,id1,id3);ALTER TABLE fktable ADD CONSTRAINT fk_253_213FOREIGN KEY (x2,x5,x3) REFERENCES pktable(id2,id1,id3);-- these should failALTER TABLE fktable ADD CONSTRAINT fk_123_231FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1);ALTER TABLE fktable ADD CONSTRAINT fk_241_132FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);DROP TABLE pktable, fktable CASCADE;-- test a tricky case: we can elide firing the FK check trigger during-- an UPDATE if the UPDATE did not change the foreign key-- field. However, we can't do this if our transaction was the one that-- created the updated row and the trigger is deferred, since our UPDATE-- will have invalidated the original newly-inserted tuple, and therefore-- cause the on-INSERT RI trigger not to be fired.CREATE TEMP TABLE pktable ( id int primary key, other int);CREATE TEMP TABLE fktable ( id int primary key, fk int references pktable deferrable initially deferred);INSERT INTO pktable VALUES (5, 10);BEGIN;-- doesn't match PK, but no error yetINSERT INTO fktable VALUES (0, 20);-- don't change FKUPDATE fktable SET id = id + 1;-- should catch error from initial INSERTCOMMIT;-- check same case when insert is in a different subtransaction than updateBEGIN;-- doesn't match PK, but no error yetINSERT INTO fktable VALUES (0, 20);-- UPDATE will be in a subxactSAVEPOINT savept1;-- don't change FKUPDATE fktable SET id = id + 1;-- should catch error from initial INSERTCOMMIT;BEGIN;-- INSERT will be in a subxactSAVEPOINT savept1;-- doesn't match PK, but no error yetINSERT INTO fktable VALUES (0, 20);RELEASE SAVEPOINT savept1;-- don't change FKUPDATE fktable SET id = id + 1;-- should catch error from initial INSERTCOMMIT;BEGIN;-- doesn't match PK, but no error yetINSERT INTO fktable VALUES (0, 20);-- UPDATE will be in a subxactSAVEPOINT savept1;-- don't change FKUPDATE fktable SET id = id + 1;-- Roll back the UPDATEROLLBACK TO savept1;-- should catch error from initial INSERTCOMMIT;-- test order of firing of FK triggers when several RI-induced changes need to-- be made to the same row. This was broken by subtransaction-related-- changes in 8.0.CREATE TEMP TABLE users ( id INT PRIMARY KEY, name VARCHAR NOT NULL);INSERT INTO users VALUES (1, 'Jozko');INSERT INTO users VALUES (2, 'Ferko');INSERT INTO users VALUES (3, 'Samko');CREATE TEMP TABLE tasks ( id INT PRIMARY KEY, owner INT REFERENCES users ON UPDATE CASCADE ON DELETE SET NULL, worker INT REFERENCES users ON UPDATE CASCADE ON DELETE SET NULL, checked_by INT REFERENCES users ON UPDATE CASCADE ON DELETE SET NULL);INSERT INTO tasks VALUES (1,1,NULL,NULL);INSERT INTO tasks VALUES (2,2,2,NULL);INSERT INTO tasks VALUES (3,3,3,3);SELECT * FROM tasks;UPDATE users SET id = 4 WHERE id = 3;SELECT * FROM tasks;DELETE FROM users WHERE id = 4;SELECT * FROM tasks;-- could fail with only 2 changes to make, if row was already updatedBEGIN;UPDATE tasks set id=id WHERE id=2;SELECT * FROM tasks;DELETE FROM users WHERE id = 2;SELECT * FROM tasks;COMMIT;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?