work around for triggers that update the same table - mysql

I am building a nba_players table in MySQL. It has a column for players height in inches (pl_ht_inches). It also has a column (pl_ht_feet) where it lists a players height in feet. For example nba_player Michael Jordan has pl_ht_feet = '6-6' and the pl_ht_inches is updated using the following statement:
update nba_players ab
inner join
feet_hieght_tb bc on ab.pl_ht_feet = bc.hieght
set
ab.pl_ht_inches = bc.total_inches
this statement updates nba_players.pl_ht_inches using table 'feet_hieght_tb' which has two columns
hieght - hieght varchar(4) with data like '6-6' which is imperial measurement
total_inches int(3) which lists height in inches. for example hieght '6-6' would be total_inches = 78.
I then used a trigger with the update statement. I subsequently found out that you cant reference the same table as the insert statement in the trigger for that table. The trigger reads as follows:
delimiter $$
create trigger
after_nba_players_insert
after insert on nba_players
for each row
begin
update nba_players ab
inner join feet_hieght_tb bc on ab.pl_ht_feet = bc.hieght
set ab.pl_ht_inches = bc.total_inches;
end$$
delimiter ;
this produces error 1442 when I attempt to insert new data into nba_players which means the trigger is updating the same table as as the insert into the nba_players table.
So then I tried to trigger the update by creating a stored procedure where I included the same update statement that i used for the trigger. I can call the procedure manually after doing an insert into nba_players and it works fine. But if I use the stored procedure in the trigger I get error 1442.
I dont want to have to remember to call the procedure every time I do an insert into nba_players and would like to automate this task if I could.
Is there an alternative to using triggers or stored procedure to update a column using data from a different table.
I have been researching generated columns but they dont allow select statements. What I mean by this is that the nba_players.pl_ht_inches is a foreign key to the table feet_hieght_tb that references total_inches where nba_players.pl_ht_feet = feet_hieght_tb.height. I would rather the foreign key update on its own rather than having to do this manually.
Any assistance will be greatly appreciated. Cheers.

Related

MySQL select statement result in after delete trigger always null

I'm having a little issue with a trigger in a MySQL database. I have a DB with two tables: "tasks" and "files". The "tasks" table have a field which is a foreign key of the primary key from the "files" table. It also sometimes may be null.
What I'm trying to acomplish is to delete in the first place a row in the "tasks" table, and after that delete the corresponding row in the "files" table using a trigger.
This is the trigger I'm using right now:
DELIMITER //
CREATE TRIGGER after_delete_file AFTER DELETE ON tasks
FOR EACH ROW
BEGIN
DECLARE fileId int;
SELECT file INTO fileId FROM tasks WHERE id=old.id;
DELETE FROM files WHERE id=fileId;
END;//
DELIMITER ;
The field "file" in the "tasks" table is the one containing the foreign key. In the examples I've been running, that field has never been null.
The problem is that the select statement always returns null. The delete statement that triggers this trigger goes fine, but the row in the "files" table is never deleted. I've tried to insert the "fieldId" variable on a testing table, and it's always saving a null value.
Is there any problem on that trigger? Maybe I'm trying to do something merely impossible?
All the help is much appreciated :)
Since it should be looping over each deleted row, why would this not work?
DELIMITER //
CREATE TRIGGER after_delete_file AFTER DELETE ON tasks
FOR EACH ROW
BEGIN
DELETE FROM files WHERE id=old.file;
END;//
DELIMITER ;
If that doesn't work, could try this:
DELIMITER //
CREATE TRIGGER after_delete_file AFTER DELETE ON tasks
FOR EACH ROW
BEGIN
DELETE FROM files INNER JOIN tasks ON files.id=tasks.file WHERE tasks.id=old.id;
END;//
DELIMITER ;
but I don't think that should be necessary.
AFTER delete means that the data is deleted, of course you can't find it. Try creating the trigger for BEFORE delete.
You could also more carefully use all of the old values rather than selecting from the table that was deleted from.

Update foreign key of different row of the same table on UPDATE

I'm using MySql, for my Database and I have a table "Person". Amongst other thing, it contains a relation to itself "Person_MarriedTo" stored as a foreigh_key;
This relation can be null since it's not everybody that's married. What I want to do is that this field can be updated automatically.
if I add A married to B, then B married to A
if B deivorce from A, then A is also divorced from B
I thought triggers would be the way to go, but I can't get my code to work the way I want it to. Any insights would be much appreciated.
Here is my code for the trigger:
USE `mydb`;
DELIMITER $$
CREATE TRIGGER `Person_BUPD` BEFORE UPDATE ON Person FOR EACH ROW
BEGIN
IF OLD.Person_MariedTo != NULL THEN
UPDATE Person SET Person_MariedTo = NULL WHERE UID_Person = OLD.Person_MariedTo;
END IF;
UPDATE Person SET Person_MariedTo = OLD.UID_Person WHERE UID_Person = NEW.Person_MariedTo;
END$$
What you are trying to do is not possible using a trigger.
Within a stored function or trigger, it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger. You need to do this some other way.
Source
See here:
MySQL - Trigger for updating same table after insert

MySQL Trigger cannot update table - getting ERROR 1442

I have the following trigger:
CREATE TRIGGER sum
AFTER INSERT
ON news
FOR EACH ROW
UPDATE news SET NEW.sum = (NEW.int_views + NEW.ext_views)/NEW.pageviews
It sums the int_views and ext_views column of a table and divides them by the total pageviews.
Whenever I try to add a new row to news, I get the following error:
ERROR 1442 (HY000) at line 3: Can't update table 'news' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
The trigger seems pretty simple to me. Is there a reason why the trigger fails to run?
The symptom is, that you are running an UPDATE (for all rows) inside a INSERT trigger - both modify the table, which is not allowed.
That said, if I guess the intention of your trigger correctly, you do not want to update all rows, but only the newly inserted row. You can achieve that easily with
CREATE TRIGGER sum
BEFORE INSERT
ON news
FOR EACH ROW
SET NEW.sum = (NEW.int_views + NEW.ext_views)/NEW.pageviews
Mind that this is a BEFORE INSERT trigger, as you want to change the row before it is written to the table.
If you try to update/insert on the same table that cause trigger to fire do not use the common sql command like
-> UPDATE TABLE_NAME SET COLUMN_NAME = VALUE WHERE CONDITION_LIST;
-> INSERT INTO TABLE_NAME VALUES("VALUE1","VALUE2");
This will not work. Only use set to assign the value of the column you update.
Example:
CREATE TRIGGER trigger_name BEFORE/AFTER INSERT/UPDATE ON table_name
FOR EACH ROW
SET NEW.COLUMN_NAME = "VALUE";
I was in a similar condition where I had to run two triggers:
UPDATE 3 fields on INSERTing a new ROW
UPDATE 3 fields on UPDATEing a ROW
After lot of efforts, I was finally able to write the TRIGGER in following way:
FOR updating values on INSERT
CREATE TRIGGER `INSERT_DISCOUNT_SERVICES` BEFORE INSERT ON `services`
FOR EACH ROW SET
NEW.discount_5_rate = (NEW.ndis_rate*0.05),
NEW.discount_10_rate=(NEW.ndis_rate*0.10),
NEW.discount_15_rate=(NEW.ndis_rate*0.15)
Similarly
FOR updating values on UPDATE
CREATE TRIGGER `UPDATE_DISCOUNTS_SERVICES` BEFORE UPDATE ON `services`
FOR EACH ROW SET
NEW.discount_5_rate = (NEW.ndis_rate*0.05),
NEW.discount_10_rate=(NEW.ndis_rate*0.10),
NEW.discount_15_rate=(NEW.ndis_rate*0.15)

mySQL trigger cannot update table : already in use by the statement that invoked the trigger

so i've edited my code
i had this problem in another trigger but this time even changing WHERE clause doesn't help
DELIMITER $$
CREATE TRIGGER pic_album_change AFTER UPDATE ON pictures
FOR EACH ROW BEGIN
UPDATE albums SET counter = counter + 1 WHERE albums.id = NEW.album_id;
UPDATE albums SET counter = counter - 1 WHERE albums.id = OLD.album_id;
END $$
DELIMITER ;
error :
<p>Error Number: 1442</p><p>Can't update table 'pictures' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
i dont see any changes on the pictures table in this trigger
i have another trigger that involves these two tables
DELIMITER $$
CREATE TRIGGER album_change
AFTER UPDATE
ON albums
FOR EACH ROW
BEGIN
UPDATE pictures
SET
level = NEW.level
WHERE
pictures.album_id = NEW.id ;
END $$
DELIMITER ;
Your WHERE clause is the wrong way round.
WHERE albums.id = NEW.album_id
would cause albums.counter to be incremented (presumably that's the number of pictures in each album).
It matters because joins on tables are not commutative — the direction of the join is important. Here you need to find the record in albums to update based on the value of the row in pictures.
While in this case there isn't really any ambiguity, SQL needs to follow rules about joins.
The issue with your second trigger is that MySQL is preventing a continuous cycle of updates. You have a trigger pic_album_change which updates albums when pictures is updated. And you have a trigger album_change which updates pictures when albums is updated. Those triggers will trigger each other.
It seems to me that the database design may need to be changed. Do you really need albums.counter when that data can be found with SELECT count(*) FROM pictures WHERE album_id=...? It should be possible to normalise data so that there no circular references in triggers. In fact triggers may not be necessary at all.

Updating joined rows in two tables from an INSERT trigger

I currently have the following MySQL query, which I would like to include in a trigger, rather than as a separate query. The query updates data in two tables which are joinable:
UPDATE `testing_names` INNER JOIN `purchase_names`
ON `testing_names`.`fulldomain` = `purchase_names`.`fulldomain`
SET
`testing_names`.`account_id` = `purchase_names`.`account_id`,
`purchase_names`.`purchase_status` = 1
WHERE `purchase_names`.`purchase_status` = 0
A row is (separately) inserted into testing_names. This row SHOULD have a corresponding entry in purchase_names. After a row is inserted into testing_names, when my UPDATE query is next run, it will update testing_names.account_id and update purchase_names.purchase_status to effectively mark this task as completed.
It makes sense to run this as part of a trigger, but I haven't been able to create a trigger that does the job.
So far, I have successfully created a trigger:
DELIMITER $$
CREATE TRIGGER `my_trigger` AFTER INSERT
ON testing_names
FOR EACH ROW BEGIN
UPDATE `testing_names` INNER JOIN `purchase_names`
ON `testing_names`.`fulldomain` = `purchase_names`.`fulldomain`
SET
`testing_names`.`account_id` = `purchase_names`.`account_id`,
`purchase_names`.`purchase_status` = 1
WHERE `purchase_names`.`purchase_status` = 0;
END$$
DELIMITER ;
but evidently running a new UPDATE query is not allowed, because upon inserting a row, I get an error: #1442 - Can't update table 'testing_names' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Unfortunately, a trigger on a table cannot update the same table.
From MySQL documentation:
Within a stored function or trigger, it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
Instead, you might be able to complete your update by having the trigger on testing_names update purchase_names and have another trigger on purchase_names update testing_names.
Try Using a Before INsert Instead