Why ON CASCADE DELETE is not working? - mysql

I want to delete rows from 2 tables in one query, so I do:
DELETE FROM form_questionnaire;
This is removing all rows from form_questionnaire but leaves rows in questionnaire. Why rows in questionnaire are not removed if there is ON DELETE CASCADE in form_questionnaire.questionnaire_id?
My tables
CREATE TABLE questionnaire(
id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
content JSON,
creator VARCHAR(50) NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE form_questionnaire(
form_id INTEGER,
questionnaire_id INTEGER,
FOREIGN KEY(form_id) REFERENCES form(id),
FOREIGN KEY(questionnaire_id) REFERENCES questionnaire(id) ON DELETE CASCADE
) ENGINE=INNODB;
database server
MySQL 5.7.21-20

You're thinking about cascades the wrong way around. What your current foreign key constraint is saying is "When you delete any row(s) in questionnaire, also delete any rows in this table (form_questionnaire) which reference those rows". That's the cascade.

I am not sure if I am understanding this incorrect OR it is your typing mistake. Foreign key will delete all rows from CHILD table (where FOREIGN KEY is defined) if related rows from master table are deleted.
That said, if you delete rows from questionnaire table, all related rows from form_questionnaire will be deleted automatically due to CASCADE DELETE.
What you have mentioned in question is opposite and does not happen so.

Related

#1452 - Cannot add or update a child row: a foreign key constraint fails the query is failing [duplicate]

I'm having a bit of a strange problem. I'm trying to add a foreign key to one table that references another, but it is failing for some reason. With my limited knowledge of MySQL, the only thing that could possibly be suspect is that there is a foreign key on a different table referencing the one I am trying to reference.
I've done a SHOW CREATE TABLE query on both tables, sourcecodes_tags is the table with the foreign key, sourcecodes is the referenced table.
CREATE TABLE `sourcecodes` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL,
`language_id` int(11) unsigned NOT NULL,
`category_id` int(11) unsigned NOT NULL,
`title` varchar(40) CHARACTER SET utf8 NOT NULL,
`description` text CHARACTER SET utf8 NOT NULL,
`views` int(11) unsigned NOT NULL,
`downloads` int(11) unsigned NOT NULL,
`time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `language_id` (`language_id`),
KEY `category_id` (`category_id`),
CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `sourcecodes_tags` (
`sourcecode_id` int(11) unsigned NOT NULL,
`tag_id` int(11) unsigned NOT NULL,
KEY `sourcecode_id` (`sourcecode_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
This is the code that generates the error:
ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
Quite likely your sourcecodes_tags table contains sourcecode_id values that no longer exists in your sourcecodes table. You have to get rid of those first.
Here's a query that can find those IDs:
SELECT DISTINCT sourcecode_id FROM
sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id
WHERE sc.id IS NULL;
I had the same issue with my MySQL database but finally, I got a solution which worked for me.
Since in my table everything was fine from the mysql point of view(both tables should use InnoDB engine and the datatype of each column should be of the same type which takes part in foreign key constraint).
The only thing that I did was to disable the foreign key check and later on enabled it after performing the foreign key operation.
Steps that I took:
SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8 Duplicates: 0 Warnings: 0
SET foreign_key_checks = 1;
Use NOT IN to find where constraints are constraining:
SELECT column FROM table WHERE column NOT IN
(SELECT intended_foreign_key FROM another_table)
so, more specifically:
SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN
(SELECT id FROM sourcecodes)
EDIT: IN and NOT IN operators are known to be much faster than the JOIN operators, as well as much easier to construct, and repeat.
Truncate the tables and then try adding the FK Constraint.
I know this solution is a bit awkward but it does work 100%. But I agree that this is not an ideal solution to deal with problem, but I hope it helps.
For me, this problem was a little different and super easy to check and solve.
You must ensure BOTH of your tables are InnoDB. If one of the tables, namely the reference table is a MyISAM, the constraint will fail.
SHOW TABLE STATUS WHERE Name = 't1';
ALTER TABLE t1 ENGINE=InnoDB;
This also happens when setting a foreign key to parent.id to child.column if the child.column has a value of 0 already and no parent.id value is 0
You would need to ensure that each child.column is NULL or has value that exists in parent.id
And now that I read the statement nos wrote, that's what he is validating.
I had the same problem today. I tested for four things, some of them already mentioned here:
Are there any values in your child column that don't exist in the parent column (besides NULL, if the child column is nullable)
Do child and parent columns have the same datatype?
Is there an index on the parent column you are referencing? MySQL seems to require this for performance reasons (http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)
And this one solved it for me: Do both tables have identical collation?
I had one table in UTF-8 and the other in iso-something. That didn't work. After changing the iso-table to UTF-8 collation the constraints could be added without problems. In my case, phpMyAdmin didn't even show the child table in iso-encoding in the dropdown for creating the foreign key constraint.
It seems there is some invalid value for the column line 0 that is not a valid foreign key so MySQL cannot set a foreign key constraint for it.
You can follow these steps:
Drop the column which you have tried to set FK constraint for.
Add it again and set its default value as NULL.
Try to set a foreign key constraint for it again.
I'd the same problem, I checked rows of my tables and found there was some incompatibility with the value of fields that I wanted to define a foreign key. I corrected those value, tried again and the problem was solved.
I end up delete all the data in my table, and run alter again. It works. Not the brilliant one, but it save a lot time, especially your application is still in development stage without any customer data.
try this
SET foreign_key_checks = 0;
ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
SET foreign_key_checks = 1;
I had this exact same problem about three different times. In each instance it was because one (or more) of my records did not conform to the new foreign key. You may want to update your existing records to follow the syntax constraints of the foreign key before trying to add the key itself. The following example should generally isolate the problem records:
SELECT * FROM (tablename)
WHERE (candidate key) <> (proposed foreign key value)
AND (candidate key) <> (next proposed foreign key value)
repeat AND (candidate key) <> (next proposed foreign key value) within your query for each value in the foreign key.
If you have a ton of records this can be difficult, but if your table is reasonably small it shouldn't take too long. I'm not super amazing in SQL syntax, but this has always isolated the issue for me.
Empty both your tables' data and run the command. It will work.
I was getting this error when using Laravel and eloquent, trying to make a foreign key link would cause a 1452. The problem was lack of data in the linked table.
Please see here for an example: http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/
You just need to answer one question:
Is your table already storing data? (Especially the table included foreign key.)
If the answer is yes, then the only thing you need to do is to delete all the records, then you are free to add any foreign key to your table.
Delete instruction: From child(which include foreign key table) to parent table.
The reason you cannot add in foreign key after data entries is due to the table inconsistency, how are you going to deal with a new foreign key on the former data-filled the table?
If the answer is no, then follow other instructions.
I was readying this solutions and this example may help.
My database have two tables (email and credit_card) with primary keys for their IDs. Another table (client) refers to this tables IDs as foreign keys. I have a reason to have the email apart from the client data.
First I insert the row data for the referenced tables (email, credit_card) then you get the ID for each, those IDs are needed in the third table (client).
If you don't insert first the rows in the referenced tables, MySQL wont be able to make the correspondences when you insert a new row in the third table that reference the foreign keys.
If you first insert the referenced rows for the referenced tables, then the row that refers to foreign keys, no error occurs.
Hope this helps.
Make sure the value is in the other table otherwise you will get this error, in the assigned corresponding column.
So if it is assigned column is assigned to a row id of another table , make sure there is a row that is in the table otherwise this error will appear.
you can try this exapmple
START TRANSACTION;
SET foreign_key_checks = 0;
ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY
(`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
SET foreign_key_checks = 1;
COMMIT;
Note : if you are using phpmyadmin just uncheck Enable foreign key checks
as example
hope this soloution fix your problem :)
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
SELECT id FROM sourcecodes);
should help to get rid of those IDs. Or if null is not allowed in sourcecode_id, then remove those rows or add those missing values to the sourcecodes table.
I had the same problem and found solution, placing NULL instead of NOT NULL on foreign key column. Here is a query:
ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
MySQL has executed this query!
In my case, I created a new table with the same structure, created the relationships with the other tables, then extracted the data in CSV from the old table that has the problem, then imported the CSV to the new table and disabled foreign key checking and disabled import interruption, all my data are inserted to the new table that has no problem successfully, then deleted the old table.
It worked for me.

Correct way to remove entry from a SQL table along with the relations

If we have TableA and TableB related by TableAB where TableAB has foreign keys for the first two table, then what's the go-to way of deleting an entry from TableA? Up to now if used a property such as IsActive with a bit to describe if the entry is still valid. However, that makes it a little problematic when there are "ghost entries" in the relation tables, such as TableAB.
How should I proceed?
One chaining table in question.
CREATE TABLE EntradaContadorCliente (
ClaveECC int AUTO_INCREMENT not null,
ClaveCliente int not null,
ClaveContador int not null,
ClaveEntrada int not null,
PRIMARY KEY (ClaveECC),
FOREIGN KEY (ClaveCliente) REFERENCES Cliente(ClaveCliente),
FOREIGN KEY (ClaveContador) REFERENCES Contador(ClaveContador),
FOREIGN KEY (ClaveEntrada) REFERENCES EntradaBitacora(ClaveEntrada)
);
Since TableA and TableB related by TableAB; which means TableAB is a chaining table. One way is to use ON DELETE CASCADE for cascading the delete operation on primary table.
Alternative is to, manually delete the entries from your chaining table once the entry has been deleted from primary table.
You can use a ALTER statement to re-create the FK constraint like
ALTER TABLE `TableAB` DROP FOREIGN KEY FK_KEY_Test;
ALTER TABLE `TableAB` ADD CONSTRAINT FK_KEY_Test FOREIGN KEY ('some_column')
REFERENCES `TableA` ('Test_column1') ON UPDATE CASCADE ON DELETE CASCADE;
From MySQL Documentation:
CASCADE: Delete or update the row from the parent table, and
automatically delete or update the matching rows in the child table.
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
first you disable all foreign key with:-
alter table table_name
nocheck constraint fk_constraint
then you delete data in parent table.

Update records with foreign keys when a record is deleted [duplicate]

I want to start using table relations in a new project.
After some googling I got 2 tables set up as InnoDB:
The keys I want to link are
->users->userid (primary)
->sessions->userid (index)
The only thing that I don't understand in this process is what the different settings for "On update" and "On delete" do
The options here are:
-- (nothing?)
Cascade (???)
Set Null (sets everything to null?)
No action (well duh...)
Restrict (???)
I basically want the data in sessions to be deleted when a user is completely deleted
This since the sessions will only be deleted when the expiration is detected by my session manager...
So if anyone can tell me what these options do it would be much appreciated.
CASCADE will propagate the change when the parent changes. (If you delete a row, rows in constrained tables that reference that row will also be deleted, etc.)
SET NULL sets the column value to NULL when a parent row goes away.
RESTRICT causes the attempted DELETE of a parent row to fail.
EDIT: You didn't ask about them, but the SQL standard defines two other actions: SET DEFAULT and NO ACTION. In MySQL, NO ACTION is equivalent to RESTRICT. (In some DBMSs, NO ACTION is a deferred check, but in MySQL all checks are immediate.) The MySQL parser accepts SET DEFAULT, but both the InnoDB and NDB engines reject those statements, so SET DEFAULT can't actually be used for either an ON UPDATE or ON DELETE constraint.
Also, note that cascading foreign key actions do not activate triggers in MySQL.
The table containing the foreign key is called the referencing or child table, and the table containing the candidate key is called the referenced or parent table.
Set NULL : Sets the column value to NULL when you delete the parent table row.
CASCADE : CASCADE will propagate the change when the parent changes. If you delete a row, rows in constrained tables that reference that row will also be deleted, etc.
RESTRICT : RESTRICT causes you can not delete a given parent row if a child row exists that references the value for that parent row.
NO ACTION : NO ACTION and RESTRICT are very much alike. when an UPDATE or DELETE statement is executed on the referenced table, the DBMS verifies at the end of the statement execution that none of the referential relationships are violated. in short child row no concern if parent row delete or update.
The three main types of referential actions for foreign key constraints in SQL are Cascade, Set Null and Restrict.
CASCADE:
When a record in the parent table is deleted, any related records in the child table will also be deleted.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT NOT NULL,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
);
SET NULL:
When a record in the parent table is deleted, any related records in the child table will be set to NULL.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE SET NULL
);
RESTRICT:
When a record in the parent table is deleted, an error will be thrown and the deletion will be prevented.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT NOT NULL,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE RESTRICT
);

Foreign Key Tables Updates

I just started learning SQL so I am a bit confused.
If I have Table A that has a primary key : CustomerID & Table B with foreign key CustomerID
I added the foreign key constraint by using CASCADE so that the foreign key should update or delete automatically when primary key is deleted or updated.
However, it only works for delete. When I add a new record in the primary field table, that record is not shown in the foreign key table, why is that ?
Corresponding rows are updated or deleted in the referencing table
when that row is updated or deleted in the parent table. CASCADE
cannot be specified if a timestamp column is part of either the
foreign key or the referenced key. ON DELETE CASCADE cannot be
specified for a table that has an INSTEAD OF DELETE trigger. ON UPDATE
CASCADE cannot be specified for tables that have INSTEAD OF UPDATE
triggers.
As mention in MSDN. They have mentioned the only update and delete operation of primary key table will affect the Foreign key table's column. If any insert made to primary key, it will not affected the foreign key. Since the Main objective in primary key and foreign key relationship
"An each every record is available in the foreign key table, it should contain corresponding record should be present in the primay key table and vice versa is not applicable".
If you insert any record to foreign key table that it will throws foreign referential integrity error. It will not allows you to insert a record in the foreign table unless and until you will corresponding record in the primary key table.
for information take look in following in MSDN links
http://msdn.microsoft.com/en-us/library/ms179610.aspx
Note:
if you want to achieve this functionality then you have write a logic in Stored procedure or trigger.
No,is not automatic add in your foreign key table , it's not make sense , for example if you have two table ,"City" and "People" , People in the City , so there must be a FK refer for People , if you add record in City e.g. New York , How is database know who's need to insert to People table?How many people? , and what this people properties? e.g. People Name?
So database can't do that automatic , you have to do it manually!

MySQL Foreign Key On Delete

I am trying to figure out relationships and deletion options.
I have two tables, User and UserStaff, with a 1:n relationship from User to UserStaff (a user can have multiple staff members).
When my User is deleted, I want to delete all of the UserStaff tables associated with that User. When my UserStaff is deleted, I don't want anything to happen to User. I understand that this is a cascading relationship, but I'm not sure which way.
i.e. Do I select the existing foreign key in my UserStaff table and make it cascading, or do I create a new foreign key in User and set that to cascading?
Yes, it's possible. You should make the FK in UserStaff table. In this way:
User Table
CREATE TABLE `User` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
UserStaff Table
CREATE TABLE `UserStaff` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`UserId` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`Id`),
KEY `UserId` (`UserId`),
CONSTRAINT `UserStaff_ibfk_1`
FOREIGN KEY (`UserId`)
REFERENCES `User` (`Id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From Wikipedia:
CASCADE
Whenever rows in the master (referenced) table are deleted (resp. updated), the respective rows of the child (referencing) table with a matching foreign key column will get deleted (resp. updated) as well. This is called a cascade delete (resp. update[2]).
Here, User is the master table, and UserStaff is the child table. So, yes, you'll want to create the foreign key in UserStaff, with ON DELETE CASCADE
It's been a while since I've used this, but here goes (btw, I use Toad for MySql - a great IDE, and it's free too - http://www.toadworld.com/Freeware/ToadforMySQLFreeware/tabid/561/Default.aspx!)
You need to add a Constraint to the User table. If you have an id column (and the corresponding foreign userid key in UserStaff) then the SouceColumn should be id, the destination table UserStaff and the destination column userid. You can then set the OnDelete action to be 'Cascade'
The other options are pretty self-explanatory - Restrict limits values to the values in the source column, Set Null sets the foreign key matches to Null and No Action does, er, nothing.
This stuff is very easy to do via the Toad IDE. I used MySqlAdmin tools for ages but recently discovered Toad (and it has diff and compare tools too!).
The ON DELETE CASCADE is specified on the foreign key in the UserStaff table. For additional info on foreign keys the MySQL documentation has a number of examples. The User table does not have a foreign key pointing to UserStaff, so it will not be affected by changes to the UserStaff table.
The easiest way might be to make two quick tables and try it out. But since you didn't I can tell you that the outcome will be that it work the way that you want to.
When you have a table User and a table UserStaff were a field in UserStaff uses a foreign key to reference a field in User; then if you delete a record from UserStaff that will be removed wihtout having any affect on the User table. The other way around will delete all records related to that record.
Short version: A field in UserStaff should reference a field in User with CASCADE