ERROR 1451: Cannot delete or update a parent row: a foreign key constraint fails - sql

CREATE TABLE `categories` (
`idcategories` INT NOT NULL AUTO_INCREMENT ,
`idparent` INT NULL ,
`description` VARCHAR(45) NULL ,
PRIMARY KEY (`idcategories`) );
ALTER TABLE `categories`
ADD CONSTRAINT `FK_idparent`
FOREIGN KEY (`idparent` )
REFERENCES `ilmercatinodelpulcino`.`categories` (`idcategories` )
ON DELETE CASCADE
ON UPDATE CASCADE
, ADD INDEX `FK_idparent` (`idparent` ASC) ;
INSERT INTO `categories` (`idcategories`, `description`)
VALUES (1, 'cat1');
INSERT INTO `categories` (`idcategories`, `idparent`, `description`)
VALUES (2, 1, 'cat1_child');
So this table represents a category, with an ID and a self pointing parent ID.
I have inserted a category cat1 and a subcategory cat1_child with parent id of cat1.
Now, I want to be able to change idcategory of cat1 from 1 to 10 and because I set the foreign key on update CASCADE, I expect that idparent of cat1_child will be set to 10 as well.
But when I do:
UPDATE `categories` SET `idcategories`=10 WHERE `idcategories`='1';
I get an error:
ERROR 1451: Cannot delete or update a parent row: a foreign key
constraint fails (categories, CONSTRAINT FK_idparent FOREIGN KEY
(idparent) REFERENCES categories (idcategories) ON DELETE
CASCADE ON UPDATE CASCADE) SQL Statement: UPDATE categories SET
idcategories=10 WHERE idcategories='1'
The delete instead work as expected and deleting cat1, cat1_child will be deleted as well.
Where is the error?
Than you.

I believe the answer is in the documentation (scroll down to the bottom):
Deviation from SQL standards: If ON UPDATE CASCADE or ON UPDATE SET
NULL recurses to update the same table it has previously updated
during the cascade, it acts like RESTRICT. This means that you cannot
use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL
operations. This is to prevent infinite loops resulting from cascaded
updates. A self-referential ON DELETE SET NULL, on the other hand, is
possible, as is a self-referential ON DELETE CASCADE. Cascading
operations may not be nested more than 15 levels deep.
Demo: http://www.sqlfiddle.com/#!2/e29db/1

I faced the same issue then i disabled the foreign key check using below query and then i was able to delete the row
SET FOREIGN_KEY_CHECKS=0;
You can also enable the foreign key check using below query
SET FOREIGN_KEY_CHECKS=1;

Related

Deleting row on Foreign key relation

I have table on which I have a foreign key constraint like below
ALTER TABLE [dbo].[Element] WITH CHECK
ADD CONSTRAINT [FK_Element_Band]
FOREIGN KEY([BandID]) REFERENCES [dbo].[Band] ([BandID])
GO
ALTER TABLE [dbo].[Element] CHECK CONSTRAINT [FK_Element_Band]
GO
Now I am trying to delete a row from the band table like this
DELETE FROM Band
WHERE TypeID = 21 AND BandUpperLimit = 10000 AND PID = 61
But I am getting a reference constraint error:
The DELETE statement conflicted with the REFERENCE constraint "FK_Element_Band". The conflict occurred in database "pricingModified", table "dbo.Element", column 'BandID'.
So this should happen if I have anything in the Elements table which is referencing Band table with the ID 21 but that's not the case since the SQL
SELECT *
FROM Element
WHERE BandID = 21
returns nothing.
Can someone please tell me why I am not able to delete row data from the parent table even though there is no reference present in the child table?
Thanks
Just specify ON DELETE CASCADE in your foreign key constraint. Then when you delete a row from the Band table it will automatically delete any child records in the Element table.
ALTER TABLE [dbo].[Element] WITH CHECK
ADD CONSTRAINT [FK_Element_Band]
FOREIGN KEY([BandID]) REFERENCES [dbo].[Band] ([BandID]) ON DELETE CASCADE
GO
Check with this query instead:
select b.*
from Element e
inner join Band b
on e.BandId = b.BandId
where b.TypeId = 21
and b.BandUpperLimit = 10000
and b.PID = 61
while creating child table
create table <child_table_name>
(
_______,
_______,
([FOREIGN KEY column_name]) [size of FOREIGN KEY column] references [parent table(primary key column_name)] on delete cascade
)
Using this you can easily delete record of fk using delete operation..
Try this, if it is successful then mark it positive...

Updating primary keys in POSTGRESQL

I have a database from previous project that I want to use in another project, from security reasons I need to update the IDs of one of the table. Problem is that the table is heavily referenced by foreign keys from other tables:
CREATE TABLE "table_table" (
"id" serial NOT NULL PRIMARY KEY,
"created" timestamp with time zone NOT NULL,
);
CREATE TABLE "table_photo" (
"id" serial NOT NULL PRIMARY KEY,
"table_id" integer NOT NULL REFERENCES "table_table" ("id") DEFERRABLE INITIALLY DEFERRED,
);
Now if I change the id on table_table the reference from table_photo won't work.
I will probably use something like this to change the IDs:
UPDATE table_table SET id = id + 15613;
I have read somewhere that I could use ON UPDATE CASCADE constraints to do this but I am not very sure how to use it.
btw: I am using Django ORM.
Get the constraint name with \d "table_photo", which shows:
Foreign-key constraints:
"table_photo_table_id_fkey" FOREIGN KEY (table_id) REFERENCES table_table(id) DEFERRABLE INITIALLY DEFERRED
Then replace it with a constraint that has on update cascade:
ALTER TABLE "table_photo"
DROP CONSTRAINT "table_photo_table_id_fkey",
ADD CONSTRAINT "table_photo_table_id_fkey"
FOREIGN KEY ("table_id")
REFERENCES "table_table"
ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED;
Now when you do your UPDATE, referenced row IDs are automatically updated. Adding an index on "table_photo"."table_id" will help a lot.
This can be slow for big tables though. An alternative if you have large tables is to do it in a couple of stages. For table A with field id that's referenced by table B's field A_id:
Add a new column, new_id, to A, with a UNIQUE constraint. Leave it nullable.
Add a new column, A_new_id to table B, giving it a foreign key constraint to A(new_id).
Populate A.new_id with the new values
Do an
UPDATE B
SET A_new_id = A.new_id
FROM A
WHERE B.A_id = A.id;
to do a joined update, setting the new ID values in B.A_new_id to match.
Drop the column B.A_id and rename B.A_new_id to B.A_id.
Drop the column A.id and rename A.new_id to A.id
Create a PRIMARY KEY constraint on the renamed A.id, USING the index created automatically before.
It's a lot more complicated, especially since for big tables you usually want to do each of these steps in batches.
If this seems too complicated, just do it with a cascading foreign key constraint like above.

postgresql and Delete statement violates foreign key constraint

I have a problem with my delete statement.
I have two tables:
table vehicule_loan(
vehicule TEXT NOT NULL UNIQUE,
);
table vehicule_uid (
id UUID NOT NULL DEFAULT uuid_generate_v4(),
vehicule TEXT NOT NULL REFERENCES vehicule_loan(vehicule) ON DELETE NO ACTION
);
When I delete a vehicule from the table vehicule_loan I want that referencing rows in the table vehicule_uid are kept.
But when I try to delete one I get this error:
ERROR: update or delete on table "vehicule_loan" violates foreign key constraint "vehicule_uid_vehicule_fkey" on table "vehicule_uid"
I think I understand the error:
After I delete a vehicule from the table vehicule_loan, the vehicule in vehicule_uid would point to nothing.
But is there a way to keep the rows in vehicule_uid ?
You should allow NULL values in the foreign key attribute and define the foreign key constraint as ON DELETE SET NULL.
I quote chapter 5.3. Constraints from the PostgreSQL manual:
There are two other options: SET NULL and SET DEFAULT. These cause the
referencing columns to be set to nulls or default values,
respectively, when the referenced row is deleted.
Could look like this:
table vehicule_uid (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
vehicule text REFERENCES vehicule_loan(vehicule) ON DELETE SET NULL
);
With this setting, when you delete a row in vehicule_loan all referencing rows in vehicule_uid remain in database.

Stop invalid data in a attribute with foreign key constraint using triggers?

How to specify a trigger which checks if the data inserted into a tables foreign key attribute, actually exists in the references table. If it exist no action should be performed , else the trigger should delete the inserted tuple.
Eg: Consider have 2 tables
R(A int Primary Key) and
S(B int Primary Key , A int Foreign Key References R(A) ) .
I have written a trigger like this :
Create Trigger DelS
BEFORE INSERT ON S
FOR EACH ROW
BEGIN
Delete FROM S where New.A <> ( Select * from R;) );
End;
I am sure I am making a mistake while specifying the inner sub query within the Begin and end Blocks of the trigger. My question is how do I make such a trigger ?
Wouldn't a foreign key constraint better achieve what you want?
ALTER TABLE [dbo].[TABLE2] WITH CHECK
ADD CONSTRAINT [FK_TABLE2_TABLE1] FOREIGN KEY([FK_COLUMN])
REFERENCES [dbo].[TABLE1] ([PK_COLUMN])
GO
This is what foreign key constraints are meant to do - specifically, not allow a record to be inserted that violate the foreign key relationship.
Note that to make this example more readable, I used different column and table names - S, A, R and B looked like a mess.

What is the best way to empty a self-referential MySQL table?

I have a self-referential MySQL table with a recursive parent_id:
CREATE TABLE `recursive` (
`id` int(11) NOT NULL auto_increment,
`parent_id` int(11) default NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `data_categorysource_parent_id` (`parent_id`),
CONSTRAINT `parent_id_refs_id_627b4293`
FOREIGN KEY (`parent_id`) REFERENCES `data_categorysource` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
During testing, I want to empty it but TRUNCATE fails:
TRUNCATE `recursive`
/* SQL Error: Cannot delete or update a parent row: a foreign key
constraint fails...
I currently have to manually delete all records, starting at the bottom of the tree working upwards. This gets onerous even with small trees.
Is there an easy way around this? I can't DROP the table and re-create it easily as other tables reference it (I have already truncated those so there should be no data integrity issues there).
Why not:
UPDATE 'recursive' SET 'parent_id' = NULL WHERE 'parent_id' IS NOT NULL;
DELETE FROM 'recursive';
?
If you just want to empty the whole thing for testing purposes use:
SET FOREIGN_KEY_CHECKS = 0;
// Execute Query
SET FOREIGN_KEY_CHECKS = 1;
This totally bypasses any foreign key checks.
Well, you could add an ON DELETE CASCADE to the FOREIGN KEY definition... at least temporarily. That would allow you to truncate the table by removing the referenced rows first.
There are other ON DELETE types as well; the default is ON DELETE NO ACTION.
Or just remove the (recursive) foreign key constraint, then truncate the table, then re-add the contraint.
Repeatedly select the rows that do not appear as parents and delete them, until the table is empty. (Assuming there are no cycles...)
delete from table_1 where date(table_1_TIME) < (select T.t_Date from (select max(date(table_1_TIME)) as t_Date from table_1 ) as T)