Error 1452 when updating a parent table using mariaDB - sql

I get error 1452 when updating a row in a parent table when running mariaDB 10.5.8. The tables are defined as follows:
> SHOW CREATE TABLE files;
files CREATE TABLE `files` (
`file_path` varchar(255) NOT NULL,
`md5` text NOT NULL,
`size` int(11) NOT NULL,
PRIMARY KEY (`file_path`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
> SHOW CREATE TABLE headlines;
headlines CREATE TABLE `headlines` (
`file_path` varchar(255) NOT NULL,
`headline_offset` int(11) NOT NULL,
-- other columns
PRIMARY KEY (`file_path`,`headline_offset`),
CONSTRAINT `headlines_ibfk_1` FOREIGN KEY (`file_path`) REFERENCES `files` (`file_path`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
> SHOW CREATE TABLE headline_closures;
headline_closures CREATE TABLE `headline_closures` (
`file_path` varchar(255) NOT NULL,
`headline_offset` int(11) NOT NULL,
`parent_offset` int(11) NOT NULL,
`depth` int(11) DEFAULT NULL,
PRIMARY KEY (`file_path`,`headline_offset`,`parent_offset`),
KEY `file_path` (`file_path`,`parent_offset`),
CONSTRAINT `headline_closures_ibfk_1` FOREIGN KEY (`file_path`, `headline_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `headline_closures_ibfk_2` FOREIGN KEY (`file_path`, `parent_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
The contents of the database (minimal example):
> SELECT * FROM files;
/path/to/foo1.org 106e9f12c9e4ff3333425115d148fbd4 6
> SELECT * FROM headlines;
/path/to/foo1.org 1 --other columns
> SELECT * FROM headline_closures;
/path/to/foo1.org 1 1 0
Executing the following produces the error (expected behavior is that the file path changes for all tables per the CASCADE clauses):
> UPDATE files SET file_path='/path/to/foo2.org' WHERE md5='106e9f12c9e4ff3333425115d148fbd4';
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`org_sql`.`headline_closures`, CONSTRAINT `headline_closures_ibfk_2` FOREIGN KEY (`file_path`, `parent_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`))
Things I've tried (per MySQL cascade update failed when foreign key column referenced in composite primary key)
Removing the second ON DELETE CASCADE ON UPDATE CASCADE from the headline_closures table (same error)
Dropping the primary key from the headline_closures table and that produced error 150 (Foreign key constraint is incorrectly formed)
I thought (1) would work because the docs state to not have multiple CASCADEs that could change a single column; I'm not sure why (2) would work. What am I not getting here?
Also, if someone could explain why this same arrangement works for SQLite and postgreSQL that would be appreciated since I don't get the same error with those ;)
Edit 1
This same behavior happens with MySQL 8.0.22 (so not just a mariaDB error, not too surprising)
I don't get the error if I take away one of the foreign keys in headline_closures (so there is still one constraint that has ON UPDATE CASCADE)
If I remove the ON UPDATE CASCADE from headline_closures_ibfk_1 instead of headline_closures_ibfk_2, the error then complains about headline_closures_ibfk_1 (where it complained about headline_closures_ibfk_2 when I took the CASCADEs away from headline_closures_ibfk_2 or if I left them on both) so it seem that the error is due to updating the parent, having the cascade propagate to the headline_closures table where the second constraint doesn't see the update and therefore complains (or something)
Edit 2:
DELETE FROM files WHERE md5='106e9f12c9e4ff3333425115d148fbd4'; works as intended with the constraints as written above (no error and the the deletion propagates to all child tables).

Related

MySQL parent child constraint

I have this table which has a parent-child structure
CREATE TABLE `testable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
I now want to make sure every parent_id references a valid id.
Then I want to have an ON UPDATE CASCADE ON DELETE CASCADE on my id column so that if I change an id, every same parent_id gets updated automatically, and same for delete.
I've tried with the basic approach as follows:
ALTER TABLE `testable`
ADD CONSTRAINT `fk_testable_1`
FOREIGN KEY (`parent_id`)
REFERENCES `testable` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE;
I can then correctly try to update a row's parent_id with a non-existant id and the constraint blocks me.
The problem is then when I try to update an id which is referenced in some parent_id, there I get the following error:
ERROR 1451: 1451: Cannot delete or update a parent row: a foreign key constraint fails
The expected behaviour I want to achieve is my row id to change, and every row with that parent_id to update to reference the new id
Worth noting that parent_id is nullable and this is a table I use to create a dynamic side menu with sub-menus for my application.

Reorder rows in database

I need to change order of rows in database table.
My table has 4 columns and 7 rows. I need to reorder these rows
pk_i_id int(10) unsigned Auto Increment
s_name varchar(255) NULL
s_heading varchar(255) NULL
s_order_type varchar(10) NULL
In Adminer, when I've changed pk_i_id value(number) something else, I'm getting this error...
Cannot delete or update a parent row: a foreign key constraint fails (`database_name`.`oc_t_item_custom_attr_categories`, CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_1` FOREIGN KEY (`fk_i_group_id`) REFERENCES `oc_t_item_custom_attr_groups` (`pk_i_id`))
Do you know how to change it ? Thank you
Edit
oc_t_item_custom_attr_categories
fk_i_group_id int(10) unsigned
fk_i_category_id int(10) unsigned
indexes
PRIMARY fk_i_group_id, fk_i_category_id
INDEX fk_i_category_id
foregin keys
fk_i_group_id oc_t_item_custom_attr_groups_2(pk_i_id) RESTRICT RESTRICT
fk_i_category_id oc_t_category(pk_i_id) RESTRICT RESTRICT
You need to change your foreign key on table database_name.oc_t_item_custom_attr_categories so that it updates along with column it references.
ALTER TABLE database_name.oc_t_item_custom_attr_categories DROP CONSTRAINT oc_t_item_custom_attr_categories_ibfk_1;
ALTER TABLE database_name.oc_t_item_custom_attr_categories
ADD CONSTRAINT oc_t_item_custom_attr_categories_ibfk_1 FOREIGN KEY (fk_i_group_id)
REFERENCES oc_t_item_custom_attr_groups (pk_i_id)
ON UPDATE CASCADE;
Since MariaDB seem to not support ADDING foreign keys after table creation, this is how it should work for you, assuming description of tables is correct:
RENAME TABLE oc_t_item_custom_attr_categories TO oc_t_item_custom_attr_categories_2;
CREATE TABLE oc_t_item_custom_attr_categories (
fk_i_group_id int(10) unsigned,
fk_i_category_id int(10) unsigned,
PRIMARY KEY(fk_i_group_id, fk_i_category_id),
INDEX (fk_i_category_id),
CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_1` FOREIGN KEY (fk_i_group_id)
REFERENCES oc_t_item_custom_attr_groups (pk_i_id)
ON UPDATE CASCADE,
CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_2` FOREIGN KEY (fk_i_category_id)
REFERENCES oc_t_category (pk_i_id)
) ENGINE = XtraDB; --change engine to what you are using
INSERT INTO oc_t_item_custom_attr_categories SELECT * FROM oc_t_item_custom_attr_categories_2;
How it works on example data in MySQL database: http://rextester.com/ZAKR50399

remove ON DELETE CASCADE

I have a child table. and foreign key there with ON DELETE CASCADE while creating the table.
There are no records either in child or parent table.
I want the primary key, foreign key to be as they are but want to remove only the CASCADING option from the child table .
is there anyway that i can Alter that child table.
Thank you.
The table:
SHOW CREATE TABLE table;
CREATE TABLE `table` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_departamento` int(11) unsigned DEFAULT NULL,
`name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `id_departamento` (`id_departamento`),
CONSTRAINT `departamentos_direcciones_pedidos_ibfk_1` FOREIGN KEY (`id_departamento`) REFERENCES `departamentos` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
First drop foreign key.
ALTER TABLE departamentos_direcciones_pedidos DROP CONSTRAINT departamentos_direcciones_pedidos_ibfk_1;
Second, create the correct foreign key
ALTER TABLE departamentos_direcciones_pedidos ADD FOREIGN KEY (id_departamento) REFERENCES departamentos(id);
ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }
The default is NO ACTION.
So try altering your child table back to default.
(Oracle) You can only alter the state of a constraint. ON DELETE is not a state. So you need to drop constraint and recreate it.
drop table t1 cascade constraints;
create table t1 (id number unique, rid number constraint t1_fk references t1(id) on delete cascade);
alter table t1 drop constraint t1_fk;
alter table t1 add constraint t1_fk foreign key(rid) references t1(id);
if you're using Oracle there are different dictionary views which might help you to recreate the constraint correctly
Export the database as a .sql file
Then press ctrl + H to replace all ON DELETE CASCADE with ""
Then drop the tables from the DB and use the new file to instantiate a new one without ON DELETE CASCADE

How can I stop the delete on a parent if a child entity that references that parent exists?

I have the following DDL that I am using with SQL Server 2012:
CREATE TABLE Subject (
[SubjectId] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (50) Not NULL,
CONSTRAINT [PK_Subject] PRIMARY KEY CLUSTERED ([SubjectId] ASC)
)
CREATE TABLE Topic (
[TopicId] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
[SubjectId] INT NOT NULL,
CONSTRAINT [PK_Topic] PRIMARY KEY CLUSTERED ([TopicId] ASC)
)
ALTER TABLE [Topic] WITH CHECK ADD CONSTRAINT [FK_TopicSubject]
FOREIGN KEY([SubjectId]) REFERENCES [Subject] ([SubjectId])
ON DELETE CASCADE
CREATE TABLE SubTopic (
[SubTopicId] INT IDENTITY (1, 1) NOT NULL,
[TopicId] INT NOT NULL,
[Name] NVARCHAR (4000) Not NULL,
CONSTRAINT [PK_SubTopic] PRIMARY KEY CLUSTERED ([SubTopicId] ASC)
)
ALTER TABLE [SubTopic] WITH CHECK ADD CONSTRAINT [FK_SubTopicTopic]
FOREIGN KEY([TopicId]) REFERENCES [Topic] ([TopicId])
ON DELETE CASCADE
When I try to run the scripts I get the following message:
{"Introducing FOREIGN KEY constraint 'FK_TopicSubject'
on table 'Topic' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
or modify other FOREIGN KEY constraints.\r\nCould not create constraint.
See previous errors."}
What I really need is for when a person tries to DELETE a subject when there are topics for the delete to fail. If I include neither DELETE ON CASCADE or DELETE NO ACTION then will this happen. If not then how can I stop the delete on subject happening if there are Topics for that subject?
Short answer is: If you don’t want cascade updates and deletions then use ON DELETE NO ACTION. Same applies for Update.
Here is a copy from MSDN article (it’s SQL Server 2000 but same rules still apply)
ON DELETE NO ACTION
Specifies that if an attempt is made to delete a row with a key referenced by foreign keys in existing rows in other tables, an error is raised and the DELETE is rolled back.
ON UPDATE NO ACTION
Specifies that if an attempt is made to update a key value in a row whose key is referenced by foreign keys in existing rows in other tables, an error is raised and the UPDATE is rolled back.
Please refer to this link. It has given a detail explanation of this error, and also has suggested to create a trigger as an alternative.
Foreign key constraint may cause cycles or multiple cascade paths?

Why is this a cyclical foreign key constraint?

I came upon this code, marked "error," in an application I'm to update. Running it on a test database gives a cyclical reference error:
The referential relationship will result in a cyclical reference that is not allowed (Constraint name = descriptions_fk_2)
I named the constraints to see which one caused the problem.
CREATE TABLE items (
id INT NOT NULL UNIQUE IDENTITY,
name NCHAR(100) NOT NULL UNIQUE,
PRIMARY KEY (id)
);
CREATE TABLE sources (
id INT NOT NULL UNIQUE IDENTITY,
item_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (item_id)
REFERENCES items(id) ON UPDATE NO ACTION ON DELETE CASCADE
);
CREATE TABLE descriptions (
id INT NOT NULL UNIQUE IDENTITY,
item_id INT NOT NULL,
source_id INT NOT NULL,
PRIMARY KEY (id),
CONSTRAINT descriptions_fk_1 FOREIGN KEY (item_id)
REFERENCES items(id) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT descriptions_fk_2 FOREIGN KEY (source_id)
REFERENCES sources(id) ON UPDATE NO ACTION ON DELETE CASCADE
);
Why is this a cyclical reference? The descriptions table is linked to two separate tables, but none of them link back to descriptions.
It's not strictly cyclical - but there are multiple cascade paths. So you could cascade delete a row in items two ways:
1) description -> item
2) description -> source -> item
And, for that reason, it's disallowed.
I believe it's a performance concern, as PostGres will allow cycles like that and will just work it out, but deletes under those circumstances can be quite slow.
For some further reading about why it's disallowed, please see this answer.