I want to run a trigger once and only once the first time a condition is satisfied.
To do this I would like to drop the trigger from within the body of the trigger itself. I have two questions: 1) is there a better way than this and 2) will anything weird happen if I drop the trigger inside the trigger body?
This is what I have so far. For context: There's another process running moving things to done and in a particular case it does not write the result so in that case I want to run a script such that when they're all done I want this trigger to read some values another table and then remove the trigger itself so that it doesn't run every single time stuff gets done normally.
CREATE TRIGGER some_trigger AFTER UPDATE ON table_name FOR EACH ROW
SELECT CASE WHEN ((SELECT count(*) FROM table_name WHERE status!='done') = 0)
THEN BEGIN
UPDATE table_name SET result = (SELECT other.result FROM table_name, other WHERE other.id = table_name.id);
DROP TRIGGER some_trigger;
END;
ELSE BEGIN END;
END CASE;
EDIT: also a third question, what does "FOR EACH ROW" mean? I only want the trigger to run once, not once per row. Looking at the docs it seems like "FOR EACH ROW" is not optional.
DROP TRIGGER cannot be performed within a Trigger.
To explain why, firstly, DROP TRIGGER causes an implicit commit, and secondly, commits cannot occur within triggers. Details below:
DROP TRIGGER causes an implicit commit
See (https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html):
The statements listed in this section (and any synonyms for them) implicitly end any transaction active in the current session, as if you had done a COMMIT before executing the statement.
...
Data definition language (DDL) statements that define or modify database objects. ALTER EVENT, ALTER FUNCTION, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER VIEW, CREATE DATABASE, CREATE EVENT, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE ROLE, CREATE SERVER, CREATE SPATIAL REFERENCE SYSTEM, CREATE TABLE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP EVENT, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP ROLE, DROP SERVER, DROP SPATIAL REFERENCE SYSTEM, DROP TABLE, DROP TRIGGER, DROP VIEW, INSTALL PLUGIN, RENAME TABLE, TRUNCATE TABLE, UNINSTALL PLUGIN.
Commits cannot occur within a trigger:
See (https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html):
The trigger cannot use statements that explicitly or implicitly begin or end a transaction, such as START TRANSACTION, COMMIT, or ROLLBACK. (ROLLBACK to SAVEPOINT is permitted because it does not end a transaction.).
Related
As you probably know, there's no syntax that modifies a MySQL trigger.
To do that, you need to execute DROP TRIGGER and then re-create it again with the new definition.
What is the right/best way of doing this, considering the following:
You cannot encapsulate these two statements in a transaction as that will be pointless (both DROP TRIGGER and CREATE TRIGGER invoke implicit transactions)
You cannot use LOCK TABLES READ as an error is triggered
Just between your DROP and CREATE TRIGGER, some other session might insert/update/delete row(s) which won't be handled by neither of your new nor old triggers.
When testing before I posted, I overlooked what type of LOCK I'm acquiring, it was READ.
So it seems using WRITE lock does the job:
delimiter $$
LOCK TABLES table1 WRITE $$
DROP TRIGGER IF EXISTS after_insert_on_table1 $$
CREATE TRIGGER after_insert_on_table1 AFTER INSERT ON table1
FOR EACH ROW
BEGIN
...
END
$$
UNLOCK TABLES $$
delimiter ;
So my recommendation is to always use this sequence when updating/modifying triggers.
I have two tables like as:
fee_master(id,cTId,feeType,amount,startDate,lastDate,fine_last_date,fine,status)
payroll(id,emId,date,loan,netSalary)
I am trying to create a trigger like as:
DELIMITER $$
DROP TRIGGER IF EXISTS test
DELIMITER $$;
CREATE TRIGGER test
BEFORE DELETE ON fee_master
FOR EACH ROW
UPDATE payroll SET loan=OLD.amount,netSalary=OLD.fine WHERE id=18;
DELIMITER $$;
delete from fee_master where id='18';
When I have run this trigger, the data is deleted from fee_master, but payroll is not updated, also I have tried to insert payroll but not working.Every times the data is deleted from fee_master.
If I change the update and delete query position with trigger then It is ok. Actually, It is not working on trigger operation.
What is the problem ?
Your syntax for UPDATE is incorrect. Multiple assignments are separated by ,, not AND.
UPDATE payroll SET loan=OLD.amount, netSalary=OLD.fine WHERE id=18;
May be you are new on triggering.
According to your question, I recommend you first read basics of triggering from here http://www.sitepoint.com/how-to-create-mysql-triggers/
Remind that, It is a stored process. You do not need to run the trigger every times,I hope you are confuse here. After creating a trigger, You have to run the master query then the trigger automatically run the next operation.
Your code is ok. And the code of Barmar also ok.The main problem your understanding.
I've encountered an interesting problem. I would like to create two triggers, trigger1 would fire on DROP TABLE and trigger2 on ALTER TABLE. I would like trigger1 and trigger2 to fire if any table is dropped or altered, but, unfortunately I don't know the syntax to do that and I couldn't find a syntax for such triggers either. In MySQL I can only write triggers which fire before/after INSERT, UPDATE, or DELETE, but now I would like to write triggers which would be applicable on database level and would fire on table events. Can somebody help me?
What you are looking for is known as "DDL Triggers". MySQL does not support them
There is this SourceForge request but I'm not sure how serious anyone is about adding it
It's not possible to use a trigger for drop statements.According to the documentation the trigger is activated on
INSERT: The trigger is activated whenever a new row is inserted into the table; for example, through INSERT, LOAD DATA, and REPLACE
statements.
UPDATE: The trigger is activated whenever a row is modified; for example, through UPDATE statements.
DELETE: The trigger is activated whenever a row is deleted from the table; for example, through DELETE and REPLACE statements.
However, DROP TABLE and TRUNCATE TABLE statements on the table do not activate this trigger, because they do not use DELETE.
It doesn't say anything about alter table, but I would expect only DML-statements to be able to fire a trigger.
PROCEDURE `pr_new_type`( IN column_name varchar(10) )
BEGIN
SET #queryText = CONCAT('ALTER TABLE `user_rights` ADD ', column_name, ' BINARY( 9 ) NULL');
PREPARE query FROM #queryText;
EXECUTE query;
DEALLOCATE PREPARE query;
END
test this
Is there a way to create MySQL trigger which triggers on either UPDATE or INSERT?
Something like
CREATE TRIGGER t_apps_affected BEFORE INSERT OR UPDATE ...
Obviously, the above don't work. So, any workarounds without creating two separate triggers?
I need this in order to update running counter on another table.
Unfortunately, there is no shorthand form - you must create multiple triggers - one for each event.
The doc says:
trigger_event indicates the kind of statement that activates the trigger. The trigger_event can be one of the following:
INSERT: The trigger is activated whenever a new row is inserted into
the table; for example, through INSERT, LOAD DATA, and REPLACE
statements.
UPDATE: The trigger is activated whenever a row is modified; for
example, through UPDATE statements.
DELETE: The trigger is activated whenever a row is deleted from the
table; for example, through DELETE and REPLACE statements. However,
DROP TABLE and TRUNCATE TABLE statements on the table do not activate
this trigger, because they do not use DELETE. Dropping a partition
does not activate DELETE triggers, either. See Section 12.1.27,
“TRUNCATE TABLE Syntax”.
While it is impossible to put a trigger on multiple events, you can define the two triggers to merely call another stored procedure and, with that, cut down on the amount of code you need to commit. Just create the separate triggers to do nothing but, say,
CALL update_counter();
and put all of your actual work into the procedure. The triggers would then be a simple
CREATE TRIGGER t_apps_affected BEFORE INSERT ON table
FOR EACH ROW
BEGIN
CALL update_counter();
END;
using MySQL 5.1.36, I am trying to write trigger which drops scratch tables form "scratch" database.
CREATE DEFINER=`root`#`localhost` TRIGGER
`jobq`.`DropScratch`
BEFORE DELETE ON jobq.jobq FOR EACH ROW
BEGIN
DECLARE tblname VARCHAR(128);
set tblname=concat('scratch.',OLD.jobname);
DROP TABLE IF EXISTS tblname;
END;
I am always getting an error:
Explicit or implicit commit is not allowed in stored function or trigger.
Can I somehow overcome this restriction?
Thank you beforehand
Arman
The primary problem here is that you are not allowed to drop a table within a trigger. That's what the error message is getting at when it says "implicit commit" is not allowed. The drop table does an implicit commit.
So you will need to figure out a different way to do this other than a trigger. One way would be to set up a cron job which compares the data in information_schema.tables to the jobq table to look for tables in the scratch DB that can be dropped, and then drop them.
I should also point out that the way you are trying to dynamically create a drop table statement will not work. That is going to drop a table named literally "tblname", not "scratch.jobname". If you want to drop a table dynamically you will need to build the drop table statement in a separate scripting language, such as python, perl, shell, etc.
Good luck!