Hi *, I am sorry to introduce myself to this list with such a long posting. And I am even more sorry to post such critical content! Forgive me.
I am developing an ORM-tool, which as a part of it's tasks, emulates ON DELETE actions of the underlying RDBMS. Accidentally I came across some wierdnesses in SQLite. After studying the documentation without satisfying results, I started to write a bunch of automated exploration tests. My conclusion is: - The order of execution of ON DELETE action is not well documented. - It often relies on the order of declaration in the DDL. - The DDL's impact on the order of execution may vary. - If two foreign keys come into conflict, SQLite silently ignores one of them instead of raising an error. Even with a more detailled documentation, I find the implementation of ON DELETE actions in a way "unstable" and "risky". Unstable, for it depends on the manifestation of a DDL. The order of foreign key declarations within an DDL however can easily be changed, which sometimes results in an surprising change of SQLite's behaviour. Think of tools auto-generating DDL from some user-defined metadata. Risky, for the implicit skipping of actions risks the user's data (especially, but not limited to, when ON DELETE RESTRICT is skipped). My questions are: Have I actually to try to emulate SQLite's current behaviour? If so: Is there hope for more detailled documentation? Or is there hope for another implementation? Here is the SQL-output of my tests. It contains some, outlining the problems I see. The SQLite version is 3.7.16. /* * Set 1. * * A table "track" declares two different foreign keys to a table "artist". * * In Set 1a, those foreign keys are built using the same column. * In Set 1b, each foreign key is built using a different column. * * Obviously, order of foreign key declarations often matters. * * The sometimes puzzling results could be avoided, if SQLite would prevent * the declaration of conflicting foreign keys from one table to another. */ /* * Set 1a. * ON DELETE conflicts with two foreign keys built using the same column. * * CASCADE vs. RESTRICT: RESTRICT wins * RESTRICT vs. CASCADE : CASCADE wins * RESTRICT vs. SET NULL: SET NULL wins * SET NULL vs. RESTRICT: RESTRICT wins * SET NULL vs. CASCADE : CASCADE wins * CASCADE vs. SET NULL: SET NULL wins * * Obviously, the order of declaration is decisive. The first declaration * is ignored; the second one matters. */ -- CASCADE vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1; /* Result: 1 */; -- RESTRICT vs. CASCADE: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO track VALUES(1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- RESTRICT vs. SET NULL: SET NULL wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO track VALUES(1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track WHERE artist IS NULL; /* Result: 1 */; -- SET NULL vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1; /* Result: 1 */; -- SET NULL vs. CASCADE: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO track VALUES(1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- CASCADE vs. SET NULL: SET NULL wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO track VALUES(1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track WHERE artist IS NULL; /* Result: 1 */; /* * Set 1b. * ON DELETE conflicts with two foreign keys built using two different columns. * * RESTRICT vs. CASCADE : CASCADE wins * CASCADE vs. RESTRICT: RESTRICT wins * RESTRICT vs. SET NULL: RESTRICT wins * SET NULL vs. RESTRICT: RESTRICT wins * SET NULL vs. CASCADE : CASCADE wins * CASCADE vs. SET NULL: CASCADE wins * * The order of declaration in this case is decisive only * if RESTRICT comes into conflict with CASCADE (see the first two tests). * SET NULL is always ignored, if there is a conflicting CASCADE or RESTRICT. * * I triangulated Set 1b with reversed columns, so that * FOREIGN KEY (artist1) ... ON DELETE x FOREIGN KEY (artist2) ... ON DELETE y * was changed to * FOREIGN KEY (artist2) ... ON DELETE x FOREIGN KEY (artist1) ... ON DELETE y * This did not have any impact on the results, so I did not put those tests * into this text. */ -- RESTRICT vs. CASCADE: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- CASCADE vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist1 = 1 AND artist2 = 1; /* Result: 1 */; -- RESTRICT vs. SET NULL: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist1 = 1 AND artist2 = 1; /* Result: 1 */; -- SET NULL vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist1 = 1 AND artist2 = 1; /* Result: 1 */; -- SET NULL vs. CASCADE: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- CASCADE vs. SET NULL: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE track (artist1,artist2, FOREIGN KEY (artist1) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (artist2) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; /* * Set 2. The triangle. * * As before, there are two tables "artist" and "track", * track declaring a foreign key to "artist". * * Now we introduce a third table "cd". * "cd" also declares a foreign key to "artist". * In Set 2a this foreign key declares ON DELETE CASCADE. * In Set 2b this foreign key declares ON DELETE SET NULL. * In Set 2c this foreign key declares ON DELETE RESTRICT. * * And we add a foreign key from "track" to "cd". * * The two foreign keys "track"->"artist" and "track"->"cd" * - are built using different columns * - and have conflicting ON DELETE actions. * * The tested question is: What happens, if there is a DELETE in "artist"? * * I have not tested SQLite's behaviour, * - if the table "cd" was created _after_ table "track" * - if the two foreign keys of table "track" were built using the same column. * Those variations could very well have an impact on the results. */ /* * Set 2a * "cd" -> "artist" with ON DELETE CASCADE * * RESTRICT vs. CASCADE : RESTRICT wins * CASCADE vs. RESTRICT: CASCADE wins * CASCADE vs. SET NULL: CASCADE wins * SET NULL vs. CASCADE : CASCADE wins * RESTRICT vs. SET NULL: RESTRICT wins * SET NULL vs. RESTRICT: RESTRICT wins * * The order of declaration in this case is (as in Set 1b) decisive only * if RESTRICT comes into conflict with CASCADE (see the first two tests). * SET NULL is always ignored, if there is a conflicting CASCADE or RESTRICT. */ -- RESTRICT vs. CASCADE: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track ; /* Result: 1 */; -- CASCADE vs. RESTRICT: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- CASCADE vs. SET NULL: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- SET NULL vs. CASCADE: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 0 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- RESTRICT vs. SET NULL: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track ; /* Result: 1 */; -- SET NULL vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd ; /* Result: 1 */; SELECT COUNT(*) AS result FROM track ; /* Result: 1 */; /* * Set 2b * "cd" -> "artist" with ON DELETE SET NULL * * RESTRICT vs. CASCADE : RESTRICT wins * CASCADE vs. RESTRICT: CASCADE wins * CASCADE vs. SET NULL: CASCADE wins * SET NULL vs. CASCADE : SET NULL wins * RESTRICT vs. SET NULL: RESTRICT wins * SET NULL vs. RESTRICT: SET NULL wins * * In this set of tests, the relevance of order is reversed: * The first declaration wins, the second one is ignored. * * Perhaps things would change, if one would change the order of CREATE TABLE ... */ -- RESTRICT vs. CASCADE: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- CASCADE vs. RESTRICT: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd WHERE artist IS NULL; /* Result: 1 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- CASCADE vs. SET NULL: CASCADE wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd WHERE artist IS NULL; /* Result: 1 */; SELECT COUNT(*) AS result FROM track ; /* Result: 0 */; -- SET NULL vs. CASCADE: SET NULL wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd WHERE artist IS NULL; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist IS NULL AND cd = 1; /* Result: 1 */; -- RESTRICT vs. SET NULL: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- SET NUL vs. RESTRICT: SET NULL wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist; SELECT COUNT(*) AS result FROM artist ; /* Result: 0 */; SELECT COUNT(*) AS result FROM cd WHERE artist IS NULL; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist IS NULL AND cd = 1; /* Result: 1 */; /* * Set 2c * "cd" -> "artist" with ON DELETE RESTRICT * * RESTRICT vs. CASCADE : RESTRICT wins * CASCADE vs. RESTRICT: RESTRICT wins * CASCADE vs. SET NULL: RESTRICT wins * SET NULL vs. CASCADE : RESTRICT wins * RESTRICT vs. SET NULL: RESTRICT wins * SET NULL vs. RESTRICT: RESTRICT wins * * In all these tests, the ON DELETE RESTRICT from "cd" to "artist" wins, * no matter how the foreign keys "track"->"artist" and "track"->"cd" * are declared. * * Perhaps things would change, if one would change the order of CREATE TABLE ... */ -- RESTRICT vs. CASCADE: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- CASCADE vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- CASCADE vs. SET NULL: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE CASCADE FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- SET NULL vs. CASCADE: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE CASCADE); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- RESTRICT vs. SET NULL: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE SET NULL); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- SET NULL vs. RESTRICT: RESTRICT wins PRAGMA foreign_keys = ON; CREATE TABLE artist (id PRIMARY KEY); INSERT INTO artist VALUES(1); CREATE TABLE cd (id PRIMARY KEY,artist, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE RESTRICT); INSERT INTO cd VALUES(1,1); CREATE TABLE track (artist,cd, FOREIGN KEY (artist) REFERENCES artist(id) ON DELETE SET NULL FOREIGN KEY (cd) REFERENCES cd(id) ON DELETE RESTRICT); INSERT INTO track VALUES(1,1); DELETE FROM artist /* Error: foreign key constraint failed */; SELECT COUNT(*) AS result FROM artist ; /* Result: 1 */; SELECT COUNT(*) AS result FROM cd WHERE artist = 1; /* Result: 1 */; SELECT COUNT(*) AS result FROM track WHERE artist = 1 AND cd = 1; /* Result: 1 */; -- kind regards - Roland Wilczek Certified ScrumMaster (CSM) Nachtigallenstraße 11 53179 Bonn Tel.: 0228 / 336 70 40 9 Mobil: 0171 / 72 36 849 _______________________________________________ sqlite-users mailing list [email protected] http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

