I have a trigger that updates another table, when it is fired, also, I want to create an scheduled event which is set at the TIME that is SELECTED from the table Assignment using the foreign key relation.
Tables looks like that:
ClassAssignment (Bridge table between Class and Assignment):
classID,
assignmentID
Assignment:
id
deadline DATETIME
CREATE TRIGGER newClassAssignment AFTER INSERT ON classassignment FOR EACH ROW
Begin
INSERT INTO StudentAssignmentSolution(studentID, assignmentID)
SELECT s.ID, NEW.assignmentID
FROM Student s
WHERE s.classID = NEW.classID;
CREATE EVENT deadlineMissed
ON SCHEDULE (select deadline from assignment where id = new.assignmentID)
DO
update StudentAssignmentSolution set solutionDate = CURDATE() assignmentId = new.assignmentID;
END
Hope it makes sense. Thank you =)
No, it's impossible in this form. The event 'schedule' parameter is literal, you can't use a subquery in it. And you can't use the output generated by this subquery - the trigger can't contain dynamic SQL.
The solution:
You create some service table.
When your trigger is fired, it inserts the data necessary to create the event into this table.
You create a basic event procedure that is scheduled often enough. This procedure takes data from the service table and, using dynamic SQL, creates the necessary event procedure.
Related
Let me put it in simplest words possible - is it possible to delete the row, which actually set On the trigger i.e. I have an AFTER INSERT ON <table2> trigger, the SQL in the trigger INSERT / UPDATE another <table1> (based on a WHERE), and finally tends to delete the entry/row in the (the row which basically fired the trigger).
Trigger SQL:
DELIMITER ||
DROP TRIGGER IF EXISTS trg_adddata_tmp ||
CREATE TRIGGER trg_adddata_tmp
AFTER INSERT ON adddata_tmp
FOR EACH ROW
BEGIN
IF EXISTS (SELECT * FROM adddata WHERE data_id = new.data_id AND account_name = new.account_name) THEN
UPDATE adddata SET data_id = new.data_id, account_name = new.account_name, user_name = new.user_name, first_name = new.first_name, last_name = new.last_name WHERE data_id = new.data_id AND account_name = new.account_name;
ELSE
INSERT INTO adddata (data_id, account_name, user_name, first_name, last_name)
VALUES(new.data_id, new.account_name, new.user_name, new.first_name, new.last_name);
END IF;
DELETE FROM adddata_tmp WHERE id = new.id;
END;
||
Without the DELETE (just above the END;) the trigger works fine - UPDATE if exist otherwise INSERT - with DELETE statement gives the following error:
Error Code: 1442
Can't update table 'adddata_tmp' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
By the way, the error is pretty self-explanatory, but still wanted to make sure if this is possible - if not this way, may be some other way around i.e. I want the adddata_tmp table to be empty (or clean-ed up) all the time (on INSERT copies the data to main adddata table)
One idea, I have in mind is, to use an EVENT to clean-up the adddata_tmp based on some status field - which gets set as the last statement in the trigger (in place of DELETE).
No, you can't do this with trigger, here's what the documentation says:
A stored function or trigger cannot modify a table that is already
being used (for reading or writing) by the statement that invoked the
function or trigger.
If adddata_tmp table needs to be empty all the time then I would not write trigger at all. Instead, I would recommend moving adddata update logic in the script/service that tries to insert the data into adddata_tmp.
update
If we are doing bulk inserts and the data (in adddata_tmp table) is not utilised anywhere else then we can write a cron job to clean up the table (i.e. the one that executes let's say every 10 minutes). Also, TRUNCATE would be more efficient (than DELETE) in this case.
There is a declared MySQL function GETUSERID() returning an integer value. How to make a record insert faster: setting the value from inside a query like
INSERT INTO ttable
(idtoset, some_other_field...)
VALUES (GETUSERID(), value1...);
or call
INSERT INTO ttable
(some_other_field...)
VALUES (value1...);
and fill idtoset by a trigger that fires before insert?
What if the query is performing multiple row insert like
INSERT INTO ttable
(idtoset, some_other_field...)
VALUES (GETUSERID(), value1...),
(GETUSERID(), value2...),
...
(GETUSERID(), valueN...);
?
Edit
I have just investigated the answer of #Rahul.
I created a ttest table with two triggers
CREATE TRIGGER `tgbi` BEFORE INSERT ON `ttest` FOR EACH ROW BEGIN
SET NEW.testint=1;
END;
CREATE TRIGGER `tgbi` BEFORE UPDATE ON `ttest` FOR EACH ROW BEGIN
SET NEW.testint=2;
END;
If I am not mistaken, should the before insert trigger call UPDATE SET the second trigger is expected to fire as well and the created testint value might be =2, but it is =1 in every inserted row. Could that mean that the engine optimises INSERT procedure and sets the value simultaneously with that set manually by query?
Appended on request of #Rick-James. The question is not about the definite function. It is actually about any function. Any function will be called same number of times if the record is inserted from trigger or from INSERT query. That is why I am wondering what is better from the point of MySQL engine - to call it manually setting the value in inserted records or filling it by means of triggers?
CREATE DEFINER=`***`#`***` FUNCTION `GETUSERID`() RETURNS int(10)
BEGIN
DECLARE id_no INT DEFAULT -1;
SELECT `id` INTO id_no FROM `tstuff`
WHERE `tstuff`.`user_name`=
(SELECT SUBSTRING_INDEX(USER(), '#', 1)) LIMIT 1;
RETURN id_no;
END
What is faster? No idea since I haven't done a bench marking on that but doing an direct INSERT operation would better to my knowledge instead of inserting and then perform an UPDATE through trigger.
Does what you are doing currently not working? you can as well make it a INSERT .. SELECT operation like
INSERT INTO ttable (idtoset, some_other_field...)
SELECT GETUSERID(), value1..., valuen FROM DUAL;
In past versions of MySQL, using a before insert trigger to populate a not nullable column didn't work as MySQL was evaluating the provided columns before the trigger. That's why whenever I have such a situation, I usually tend to go with functions instead of triggers.
From a performance point of view, since the before insert trigger is evaluated before actually writing data so the time needed to perform this is almost the same as immediately getting the value with the function and without trigger. But if all you are doing in the trigger is set the user ID, then I really see no reason to use a trigger.
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
I'm new to working with triggers and am having a hard time understanding how to write a trigger to update a field in one table, when a record is inserted in another.
To elaborate, I have 2 tables: servTickets and servTicketNotes.
servTickets has several text fields for customer, contact, phone, email, problem description, status, etc...the PK in this table is an INT field called callID.
servTicketNotes has only 2 fields - again, the PK is an INT field 'callID' and there is a BLOB field called image which stores an image of a service report.
What I'm struggling to do is have a trigger update the status field in servTickets with a value of Closed when a new record is inserted into servTicketNotes.
I'm confused if this is an INSERT AFTER or BEFORE or BOTH scenario, but basically if a report is sent in (thereby creating a record in servTicketNotes, I want the trigger to seek out the record with the same callID in the servTickets table and change the value of status to 'Closed'.
This seems like it should be so simple, but I can't seem to grasp how to get started...
Thanks in advance for your help/guidance!
is it probably a POST trigger - which means:
AFTER you have committed the incoming record, you want to take further action - i.e. inserting into the other table.
if you do it PRE commit, then you would worry about some error happening on the Notes and you might end up with an incorrect update to the status.
You can do this with an AFTER INSERT trigger. Try something like this:
DELIMITER $$
DROP TRIGGER IF EXISTS tr_a_ins_servTicketNotes $$
CREATE TRIGGER pabeta.tr_a_ins_servTicketNotes AFTER INSERT ON servTicketNotes FOR EACH ROW BEGIN
update servTickets
set status = 'Closed'
where callID = NEW.callID;
END $$
DELIMITER ;
I want to save the mysql query used to delete a row in a table:
Example:
CREATE TRIGGER `table_DEL` BEFORE DELETE ON `table`
FOR EACH ROW BEGIN
INSERT INTO db_bk.table
SELECT *,NOW(),QUERY()
FROM db.table
WHERE table_id= OLD.table_id;
END
As you understand, I want to now if exists a query() function or another method to retrieve the query that activate the trigger (the exact delete query)
Thank you very much
As #devart said - such a function doesn't exist. If you are worried about who will delete from your table then restrict the 'delete' permission to one account. Then you can control how records are removed and when.