How to ignore foreign constraints and add NULL instead - mysql

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!

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....

Delete from another table when deleting with foreign keys

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?

MYSQL - on update one table automatically delete rows in second table

I have two tables in relation 1:n
create table A (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
data VARCHAR(32),
data2 INTEGER,
INDEX (id)
);
CREATE TABLE B (
A_id BINGINT,
some_data DOUBLE,
INDEX (A_id),
FOREIGN KEY (A_id) REFERENCES A(id) ON DELETE CASCADE
);
If i update a row in table A then i need to delete all records from table B with same id from table A. What is the best way to solve it?
i dont know if i should use a trigger or an event.
You need a trigger on table A:
DELIMITER //
CREATE TRIGGER t BEFORE UPDATE ON A
FOR EACH ROW
BEGIN
DELETE FROM B WHERE a_id = NEW.id;
END
//
DELIMITER ;

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 problem rails

I'm trying to add foreign keys to my table using the following code:
constraint_name = "fk_#{from_table}_#{to_table}"
execute %{
CREATE TRIGGER #{constraint_name}_insert
BEFORE INSERT ON #{from_table}
FOR EACH ROW BEGIN
SELECT
RAISE(ABORT, "constraint violation: #{constraint_name}")
WHERE
(SELECT id FROM #{to_table} WHERE
id = NEW.#{from_column}) IS NULL
END
}
I'm getting the following error:
Mysql2::Error: Not allowed to return a result set from a trigger:
CREATE TRIGGER fk_brands_products_insert
BEFORE INSERT ON brands
FOR EACH ROW BEGIN
SELECT
RAISE(ABORT, "constraint violation: fk_brands_products")
FROM brands
WHERE
(SELECT id FROM products WHERE id = NEW.brand_id) IS NULL;
END;
What is wrong with my SQL script?
You can add a MySQL Foreign Key constraint like this:
ALTER TABLE #{from_table}
ADD CONSTRAINT #{constraint_name} FOREIGN KEY
(#{from_column}) REFERENCES #{to_table}(id)
This will constrain from_column on from_table to values in id in #{to_table}.
P.S: If you don't want to name the CONSTRAINT you can do this:
ALTER TABLE #{from_table}
ADD FOREIGN KEY
(#{from_column}) REFERENCES #{to_table}(id)
As the error states, a trigger is not allowed to return a result set. Even though you are raising a error, MySql doesn't like the SELECT statement. Try using a IF:
IF EXISTS(SELECT id FROM #{to_table} WHERE
id = NEW.#{from_column}) = 0 THEN
RAISE(ABORT, "constraint violation: #{constraint_name}");
END IF;