Delete from another table when deleting with foreign keys - mysql

I have a problem when I'm trying to delete some information in my schema with foreign keys.
Here are my Tables
CREATE TABLE tb_class (class_ID INT PRIMARY KEY);
CREATE TABLE tb_product (fingerprint VARCHAR(255) PRIMARY KEY);
CREATE TABLE tb_class_product (class_ID INT,
fingerprint VARCHAR(255),
PRIMARY KEY (class_ID, fingerprint),
UNIQUE INDEX tb_class_product_UNIQUE (fingerprint ASC),
FOREIGN KEY (class_ID) REFERENCES tb_class(class_ID)
ON UPDATE CASCADE
ON DELETE CASCADE,
FOREIGN KEY (fingerprint) REFERENCES tb_product(fingerprint)
ON UPDATE CASCADE
ON DELETE CASCADE);
When i delete a class_ID in tb_class, I want that the information in tb_class_product AND the fingerprint in tb_product are automatically deleted.
I have already tried to add the following Trigger to tb_class_product, but without success
DELIMITER //
CREATE TRIGGER tb_class_product_after_delete
AFTER DELETE ON tb_class_product FOR EACH ROW
BEGIN
DELETE FROM tb_product WHERE tb_product.fingerprint=old.fingerprint;
END; //
DELIMITER ;
--------EDIT--------
Ok. I figured out that the cascade foreign key only delete foreign key entrys when the primary key is deleted, but it doesn't delete the primary key when the foreign key is deleted.
Besides, i have found that when a cascade foreign key is deleted, the trigger doesn't operate.
Now i have found a solution that works for me.
CREATE TABLE tb_class (class_ID INT PRIMARY KEY);
CREATE TABLE tb_product (fingerprint VARCHAR(255) PRIMARY KEY);
CREATE TABLE tb_class_product (class_ID INT,
fingerprint VARCHAR(255),
PRIMARY KEY (class_ID, fingerprint),
UNIQUE INDEX tb_class_product_UNIQUE (fingerprint ASC),
FOREIGN KEY (class_ID) REFERENCES tb_class(class_ID),
FOREIGN KEY (fingerprint) REFERENCES tb_product(fingerprint));
DELIMITER //
CREATE TRIGGER tb_class_product_before_delete
BEFORE DELETE ON tb_class_product FOR EACH ROW
BEGIN
IF #deleting_from_product IS NULL THEN
SET #deleting_from_class_product=1;
DELETE FROM tb_product WHERE tb_product.fingerprint=old.fingerprint;
SET #deleting_from_class_product=NULL;
END IF;
END; //
DELIMITER ;
DELIMITER //
CREATE TRIGGER tb_class_before_delete
BEFORE DELETE tb_class FOR EACH ROW
BEGIN
DELETE FROM tb_class_product WHERE tb_class_product.class_ID=old.class_ID;
END; //
DELIMITER ;
DELIMITER //
CREATE TRIGGER tb_product_before_delete
BEFORE DELETE tb_product FOR EACH ROW
BEGIN
IF #deleting_from_class_product IS NULL THEN
SET #deleting_from_product=1;
DELETE FROM tb_class_product WHERE tb_class_product.fingerprint=old.fingerprint:
SET #deleting_from_product=NULL;
END IF;
END; //
DELIMITER ;

With the indexes declared in the way you have described, the data should be automatically deleted from the other tables.
Could you please give the mysql version you are using, and the say what is the effect of the delete - does it throw an error?

Related

Trigger not firing in MySQL

I've got a problem with a trigger in MySQL.
My table is the following :
CREATE TABLE IF NOT EXISTS Possessioncartes (
id_carte SMALLINT UNSIGNED,
PRIMARY KEY (id_carte, pseudonyme),
CONSTRAINT fk_inv_carte_id_possession FOREIGN KEY (id_carte) REFERENCES Cartes(id_carte) on delete cascade on update cascade,
pseudonyme VARCHAR(40),
CONSTRAINT fk_inv_carte_pseudo_possession FOREIGN KEY (pseudonyme) REFERENCES Joueurs(pseudonyme) on delete cascade on update cascade,
date_possession DATETIME NOT NULL,
methode_possession VARCHAR(20),
date_non_possession DATETIME,
etat SMALLINT UNSIGNED DEFAULT 1 NOT NULL
);
and my trigger :
create trigger posseder after insert on Possessioncartes
for each row begin
set #date_non_possession = new.date_possession
where #id_carte = new.id_carte;
end$$
( When I add a new card to the table, the trigger should update all the rows that has the same ID )
when I tried to add a new row, I got no errors but no row was updated.
I tried omitting the # but I got an "unknown system variable" error.
Thanks for your time.
Triggers cannot modify the table they are "ON", nor any table involved in the query that triggered them.
For example an update trigger on A, cannot modify B for an update statement like UPDATE A INNER JOIN B ON something SET A.x = somethingelse....

How to ignore foreign constraints and add NULL instead

I have two tables which share same primary/foreign key for ID:
Table1: PRIMARY KEY (id));
Table2: FOREIGN KEY (ident) REFERENCES table1(id);
I am trying to create a trigger in order to let me insert new row with non existing primary key and set on that field NULL but i am getting:
Cannot add or update a child row: a foreign key constraint fails error.
How can i solve this issue ?
this is what i tried but so far:
DELIMITER $$
CREATE TRIGGER t1 BEFORE INSERT on table1
FOR EACH ROW
BEGIN
IF NEW.ident!= (
SELECT ident
FROM dimos
WHERE ident NOT IN (
SELECT id
FROM table1
)
)
THEN
SET NEW.ident = 'NULL';
END IF;
END $$
DELIMITER ;
so i expect to get all field in a row expert the foreign key, foreign key must be null!

MySQL: update on a table with multiple foreign key dependencies

Below is the simplified picture of the relationships I have in my DB:
create table attribute (id int auto_increment, primary key (id));
create table state_sample (id int auto_increment, primary key(id));
create table state_sample_attribute (
state_sample_id int,
attribute_id int,
primary key(state_sample_id, attribute_id),
foreign key (state_sample_id) references state_sample(id) on update cascade,
foreign key (attribute_id) references attribute(id) on update cascade
);
create table note (
id int auto_increment,
state_sample_id int,
attribute_id int,
primary key(id),
foreign key (state_sample_id) references state_sample(id) on update cascade,
foreign key (state_sample_id, attribute_id)
references state_sample_attribute(state_sample_id, attribute_id) on update cascade
);
insert into attribute values (1);
insert into state_sample values (1);
insert into state_sample_attribute values (1, 1);
insert into note values (1, 1, 1);
Whenever I try to update the ss table, it fails:
update state_sample set id = 2;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`demotemplate`.`note`, CONSTRAINT `note_ibfk_1` FOREIGN KEY (`ss_id`) REFERENCES `ss` (`id`) ON UPDATE CASCADE)
As far as I understand, this is what happens:
It tries to set state_sample.id = 2.
It sees the cascade to note and tries to update note.state_sample_id.
However, note.state_sample_id is also involved in the foreign key to to state_sample_attribute(state_sample_id, attribute_id), so it goes to check whether that's still valid.
As state_sample_attribute.state_sample_id has not yet been updated, the constraint fails.
Is my assumption correct? And if so, is there a way to work this around?
Give the ssa table its own id primary key, and use that in the foreign key in notes, rather than referencing the ss_id and a_id columns.
create table ssa (
id int auto_increment,
ss_id int,
a_id int,
primary key (id),
unique key (ss_id, a_id),
foreign key (ss_id) references ss(id) on update cascade,
foreign key (a_id) references a(id) on update cascade);
create table note (
id int auto_increment,
ss_id int,
ssa_id int,
primary key(id),
foreign key (ss_id) references ss(id) on update cascade,
foreign key (ssa_id) references ssa(id) on update cascade);
Now you don't have the redundant dependency.
It's also not clear that note needs ss_id at all, since it's redundant with the related ssa row.
Try
DISABLE KEYS
or
SET FOREIGN_KEY_CHECKS=0;
make sure to turn it on
SET FOREIGN_KEY_CHECKS=1;
after.
What solved it in the end is dropping the extra FK:
alter table note drop foreign key (state_sample_id) references state_sample(id);

Fail to trigger BEFORE INSERT INTO a table that only has one auto increment column

I'm planning to make a notification system that sends out different types of messages to users (private messages among users, message about their posts being published etc) What I'm looking for is some sort of conditional foreign key on the column this_id in notification table so that it can find a specific row from either table comments or pm, and I have found this thread that's exactly what I want. So I create a table "supertable" with just one column (SERIAL PRIMARY KEY) to be referenced by comments and PM. And to make sure a new row is insert into the supertable first to generate a key before any new row inserts into either comments and PM, I set up two BEFORE INSERT INTO triggers
CREATE TRIGGER `before_insert_comments`
BEFORE INSERT ON `comments`
FOR EACH ROW BEGIN
INSERT INTO supertable (this_id) VALUES ('')
END;
CREATE TRIGGER `before_insert_pm`
BEFORE INSERT ON `PM`
FOR EACH ROW BEGIN
INSERT INTO supertable (this_id) VALUES ('')
END;
But when inserting a record into table comments or PM, I'm still getting the error
Cannot add or update a child row: a foreign key constraint fails ( CONSTRAINT comments FOREIGN KEY (this_id) REFERENCES supertable (this_id) ON DELETE CASCADE ON UPDATE CASCADE). Anyone know what's the problem with the triggers?
Table schema
CREATE TABLE notification (
id INT NOT NULL AUTO_INCREMENT,
this_id SERIAL PRIMARY KEY,
user_id INT,
is_read TINYINT,
FOREIGN KEY (this_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE supertable (
this_id SERIAL PRIMARY KEY
);
CREATE TABLE comments (
this_id SERIAL PRIMARY KEY,
user_id INT ,
post TEXT,
is_approved TINYINT,
...
FOREIGN KEY (this_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE PM (
this_id SERIAL PRIMARY KEY,
sender_id INT,
recipient_id INT ,
msg TEXT,
...
FOREIGN KEY (this_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
Check again your column mapping. Few key to point here.
your notification table primary key should set to id instead of this_foreign_id(I rename it to avoid confuse).
datatype for this_foreign_id should be BIGINT UNSIGNED to map with SERIAL, since 1 table only can have 1 auto increment column and it should be primary key.
on your trigger, insert null instead of '' cause SERIAL column is meant for BIGINT UNSIGNED
Let me know if it work.
CREATE TABLE supertable (
this_id SERIAL PRIMARY KEY
);
CREATE TABLE notification (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
this_foreign_id BIGINT UNSIGNED,
user_id INT,
is_read TINYINT,
FOREIGN KEY (this_foreign_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE comments (
this_id SERIAL PRIMARY KEY,
user_id INT ,
post TEXT,
is_approved TINYINT,
FOREIGN KEY (this_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE PM (
this_id SERIAL PRIMARY KEY,
sender_id INT,
recipient_id INT ,
msg TEXT,
FOREIGN KEY (this_id) REFERENCES supertable(this_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TRIGGER before_insert_comments
BEGIN
BEFORE INSERT ON comments
FOR EACH ROW BEGIN
INSERT INTO supertable (this_id) VALUES (NULL);
END;
CREATE TRIGGER before_insert_pm
BEGIN
BEFORE INSERT ON PM
FOR EACH ROW BEGIN
INSERT INTO supertable (this_id) VALUES (NULL);
END;

mysql foreign key constraints

I have set foreign key integrity in a table. But i am able to delete data from the master table, which is reference in child table..
What would be the problem
Actually it should say error on deletion like all referenced table data has to be deleted.
Did you specify ON DELETE CASCADE ? when you created your FK? Don't know which engine you are using either
example
CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
) ENGINE=INNODB;
More here http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
mysql dont do it for you ,
you need declare trigger on delete action
before delete trigger example :
http://www.java2s.com/Code/Oracle/Trigger/Createabeforedeletetrigger.htm