Delete, upon foreign key constraint update - mysql

MySQL offers the following:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
Does MySQL offer something similar for DELETE which would attempt to delete and upon foreign key constraint, update the record in the table which was attempted to be deleted?
For instance...
DELETE FROM table1 WHERE idtable1 = 123;
IF(foreign key constraint) { //pseudo code...
UPDATE table1 SET deleted=1 WHERE idtable1 = 123;
}
CREATE TABLE IF NOT EXISTS table1 (
idtable1 INT NOT NULL,
data VARCHAR(45) NULL,
deleted TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (idtable1))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS table2 (
idtable2 INT NOT NULL,
table1_idtable1 INT NOT NULL,
data VARCHAR(45) NULL,
INDEX fk_table2_table1_idx (table1_idtable1 ASC),
CONSTRAINT fk_table2_table1
FOREIGN KEY (table1_idtable1)
REFERENCES table1 (idtable1)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;

If I understand correctly, you want a cascading foreign constraint on delete and/or update:
CREATE TABLE IF NOT EXISTS table2 (
idtable2 INT NOT NULL,
table1_idtable1 INT NOT NULL,
data VARCHAR(45) NULL,
INDEX fk_table2_table1_idx (table1_idtable1 ASC),
CONSTRAINT fk_table2_table1
FOREIGN KEY (table1_idtable1)
REFERENCES table1 (idtable1)
ON DELETE CASCADE
ON UPDATE CASCADE
);
This will delete the row in table2 when the corresponding row in table1 is deleted.
You can read about the different types of foreign key constraints in the documentation.

Related

How to add columns from one MySQL table to another without duplicates?

There are two tables. It is necessary to insert two fields from one to the other so that duplicates do not appear. I tried those methods that are described for
USING INSERT IGNORE
Using replace
USING INSERT ... on duplicate key update
But I didn't succeed. For example, it ignore duplicate and write these:
REPLACE INTO user_favorites
(user_id, partner_id)
SELECT id, partner_id FROM users
How to do it?
1 table
create table local.users
(
id int auto_increment,
name varchar(255) null,
email varchar(255) null,
password varchar(255) null,
partner_id int null,
constraint users_email_unique
unique (email),
constraint users_id_uindex
unique (id)
)
alter table local.users
add primary key (id);
2 table
create table local.user_favorites
(
id int auto_increment,
user_id int null,
partner_id int null,
constraint user_favorites_id_uindex
unique (id),
constraint user_favorites_partners_id_fk
foreign key (partner_id) references local.partners (id)
on update cascade on delete cascade,
constraint user_favorites_users_id_fk
foreign key (user_id) references local.users (id)
on update cascade on delete cascade
);
alter table local.user_favorites
add primary key (id);
insert ignore and insert ... on duplicate key and replace all detect duplicates by whatever unique key constraints you have. Right now, your only unique constraint in user_favorites is the primary key id, which obviously doesn't help.
Add a unique constraint on user_id and partner_id:
alter table local.user_favorites add unique (user_id,partner_id);
If that fails, you already have duplicates that you will need to clean up first.
Then do any of the things you tried to add the rows from users.
You can first add empty columns and then update corresponding values by join operation. Like this:
ALTER TABLE user_favorites ADD COLUMN
name VARCHAR(255) NULL,
email VARCHAR(255) NULL,
password VARCHAR(255) NULL;
CONSTRAINT users_email_unique UNIQUE(email);
UPDATE user_favorites tb1
INNER JOIN users tb2 ON tb1.user_id = tb2.id
AND tb1.partner_id = tb2.partner_id
SET tb1.name = tb2.name
tb1.email = tb2.email
tb1.password = tb2.password;
Reference here: https://www.tutorialspoint.com/can-we-add-a-column-to-a-table-from-another-table-in-mysql

MySQL doesn't prevent deletion of rows where primary key is associated with another table

tested this on postgreSQL and it doesn't let me delete any row(primary key) associated with another table. Is MySQL different or is there is a way to do that here in Mysql?.
CREATE TABLE account (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30)
);
CREATE TABLE transaction (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
account_id BIGINT REFERENCES account(id)
);
INSERT INTO account (name) VALUES ('john'); //account_id = 1
INSERT INTO transaction (account_id) VALUES (1);
DELETE FROM account where id = 1;
);
when I delete an account row in account table, mySQL doesn't prevent the deletion of it.
Here is the example for MYSQL. You need add the foreign key with update and delete constrains. You can also read through the documents for more details. Foreign Key
CREATE TABLE account (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30)
);
CREATE TABLE transaction (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
account_id BIGINT,
FOREIGN KEY (account_id) REFERENCES account(id) ON UPDATE CASCADE ON DELETE RESTRICT
);
INSERT INTO account (name) VALUES ('john');
INSERT INTO transaction (account_id) VALUES (1);
DELETE FROM account where id = 1;
-- 18:32:14 DELETE FROM account where id = 1 Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails (`test`.`transaction`, CONSTRAINT `transaction_ibfk_1` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON UPDATE CASCADE) 0.039 sec

How to migrate IDs from JOIN table into foreign key column in MySQL

I have the following tables in my MySQL database:
CREATE TABLE `User` (
`id` char(25) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`(191))
);
CREATE TABLE `Post` (
`id` char(25) NOT NULL,
`authorId` char(25) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `authorId` (`authorId`),
CONSTRAINT `Post_ibfk_1` FOREIGN KEY (`authorId`) REFERENCES `User` (`id`)
);
CREATE TABLE `_PostToUser` (
`A` char(25) CHARACTER SET utf8 NOT NULL,
`B` char(25) CHARACTER SET utf8 NOT NULL,
UNIQUE KEY `PostToUser_AB_unique` (`A`,`B`),
KEY `B` (`B`),
CONSTRAINT `_PostToUser_ibfk_1` FOREIGN KEY (`A`) REFERENCES `Post` (`id`) ON DELETE CASCADE,
CONSTRAINT `_PostToUser_ibfk_2` FOREIGN KEY (`B`) REFERENCES `User` (`id`) ON DELETE CASCADE
);
The relationship between User and Post right now is managed via the _PostToUser JOIN table.
However, I want to get rid of this extra JOIN table and simply have a foreign key reference from Post to User, so I ran this query to create the foreign key:
ALTER TABLE `Post` ADD COLUMN `authorId` char(25);
ALTER TABLE `Post` ADD FOREIGN KEY (`authorId`) REFERENCES `User` (`id`);
Now, I'm wondering what SQL query I need to run in order to migrate the data from the JOIN table to the new authorId column? If I understand correctly, I need a query that reads all the rows from the _PostToUser relation table and for each row:
Finds the respective Post record by looking up the value from column A
Inserts the value from column B as the value for authorId into that Post record
Note that I am aware that this changes the relationship from m-n and restricts it to 1-n: One post can at most have one author. One author/user can write many posts.
I'm basically looking for the equivalent of this PostgreSQL statement:
UPDATE "Post" post
SET "authorId" = post_to_user."B"
FROM "_PostToUser" post_to_user
WHERE post_to_user."A" = post."id";
Ensure that _PostToUser.A values are unique (no duplicated values). If exists - edit your data (remove excess records, for example).
Execute
UPDATE Post, _PostToUser
SET Post.authorId = _PostToUser.B
WHERE Post.id = _PostToUser.A
Ensure that there is no NULLs in Post.authorId

Add foreign key constraint if it is not existing

I want to create a foreign key from 1 table, but only if it does not exist.
Tables are created like that:
CREATE TABLE
IF NOT EXISTS PEs (
id INT(20) AUTO_INCREMENT PRIMARY KEY,
Name varchar(20),
Message varchar(30),
CoordsX double(9,6) SIGNED,
CoordsY double(9,6) SIGNED,
CoordsZ double(9,6) SIGNED,
Status smallint(1) DEFAULT 1,
world varchar(20)
) ENGINE = InnoDB;
CREATE TABLE
IF NOT EXISTS`rh_pe`.`attributes` (
`toid` INT(20) NOT NULL,
`Kommentar` VARCHAR(60) NOT NULL,
`Aktion` varchar(10) NOT NULL,
`Person1` INT NOT NULL,
`Person2` INT
) ENGINE = InnoDB;
The Foreign key should be like so:
ALTER TABLE `attributes`
ADD CONSTRAINT `Const`
FOREIGN KEY (`toid`) REFERENCES `pes`(`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT;
To create the foreign key, I tried the following two options:
IF NOT EXISTS(
ALTER TABLE `attributes`
ADD CONSTRAINT `Const`
FOREIGN KEY (`toid`) REFERENCES `pes`(`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT
);
and
ALTER TABLE `attributes`
ADD CONSTRAINT `Const`
FOREIGN KEY
IF NOT EXISTS (`toid`) REFERENCES `pes`(`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT
But none of them work.
Any Ideas on how I could create the constraint only if it does not exist?
Both of your table examples have the same name, so I suposed that your second table name is "pes" as you mention in your constraint examples. This one should work:
IF NOT EXISTS (SELECT * FROM sys.objects o WHERE o.object_id = object_id(N'`rh_pe`.`Const`') AND OBJECTPROPERTY(o.object_id, N'IsForeignKey') = 1)
BEGIN
ALTER TABLE `rh_pe`.`attributes` ADD CONSTRAINT `Const` FOREIGN KEY (`toid`) REFERENCES `rh_pe`.`pes`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT;
END
I haven't used the "if (not) exists" clausule for this but you can find a similar question here: If Foreign Key Not Exist Then Add Foreign Key Constraint(Or Drop a Foreign Key Constraint If Exist) without using Name?

Change value of primary key (ID of a particular record) when foreign key constraints exist

Here's the basic gist of what I'm trying to do:
create table main(id char(1) primary key);
create table other (
id int primary key auto_increment,
main_id char(1),
key m (main_id),
constraint fk foreign key (main_id) references main(id)
);
insert into main(id) values('a');
insert into other(main_id) values('a');
update main inner join other on other.main_id=main.id
set main.id='b', other.main_id='b'
where main.id='a';
This results in a foreign key constraint failure. Is there any way to accomplish this without dropping the foreign keys (not really an option on my large production database)?
You can do this simply by temporarily setting foreign_key_checks=0 in your session:
set foreign_key_checks=0;
update main inner join other on other.main_id=main.id
set main.id='b', other.main_id='b'
where main.id='a';
Another option is to configure the foreign key with the ON UPDATE CASCADE option so that if the primary key is updated on the parent table it will cascade to the child table:
create table main(id char(1) primary key);
create table other (
id int primary key auto_increment,
main_id char(1),
key m (main_id),
constraint fk foreign key (main_id) references main(id) on update cascade
);