MySQl Trigger help needed - mysql

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!

Related

Drop a trigger from within the trigger body

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

How to rename two tables in one atomic operation in MySQL

I need to rename two tables in one atomic operation so that user will never be able to see the database in its intermediate state.
I'm using MySQL and noticed that this case is perfectly described in the documentation:
13.3.3 Statements That Cause an Implicit Commit
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 DATABASE ... UPGRADE DATA DIRECTORY NAME,
ALTER EVENT, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER VIEW,
CREATE DATABASE, CREATE EVENT, CREATE INDEX, CREATE PROCEDURE, CREATE
SERVER, CREATE TABLE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP
EVENT, DROP INDEX, DROP PROCEDURE, DROP SERVER, DROP TABLE, DROP
TRIGGER, DROP VIEW, INSTALL PLUGIN (as of MySQL 5.7.6), RENAME TABLE,
TRUNCATE TABLE, UNINSTALL PLUGIN (as of MySQL 5.7.6).
But maybe there's some kind of workaround or something like this?
My situation looks like this:
I have a current data set in the table named current
I gathered a new data set in the table named next
I need to rename the current table to the current_%current_date_time% and the next table to the current in one atomic operation
Well, easy...
RENAME TABLE current TO current_20151221, next TO current;
as is stated in the manual. There it says that it's an atomic operation. Just to clear this up, implicit commits have nothing to do with it. That's a different story. That just says, that those statements end an open transaction.

mysql drop table if exists inside procedure

I'm trying to apply a nested set model example with procedures. I've found many of them with this technique and in the process I've found a problem. Every time I call the procedure I get unknown table XXX. When I create the procedure I got no problem at all. The quick example:
CREATE PROCEDURE `sp_getRoleTree` (IN root INT)
READS SQL DATA
BEGIN
DECLARE rows SMALLINT DEFAULT 0;
DROP TABLE IF EXISTS ROLE_TREE;
CREATE TABLE ROLE_TREE (
nodeID INT PRIMARY KEY
) ENGINE=HEAP;
INSERT INTO ROLE_TREE VALUES (root);
SELECT * FROM ROLE_TREE;
DROP TABLE ROLE_TREE;
END;
So my question is, am I doing something wrong here (it's example code), can I disable the warning on the if exists if the code is fine? Is there a special looping inside the procedures that's causing these kind of warnings?
As a work around: try to truncate table instead of re-creating.
Do not use DROP TABLE/CREATE TABLE. Create this table once (or when you need it) and use TRUNCATE TABLE command.
MySQL generates a warning when using DROP TABLE IF EXISTS tbl; when the table does not exist. This can be confusing and perhaps counter intuitive, but it is the expected behavior.
From http://dev.mysql.com/doc/refman/5.5/en/drop-table.html
Use IF EXISTS to prevent an error from occurring for tables that do not exist. A NOTE is generated for each nonexistent table when using IF EXISTS. See Section 13.7.5.41, SHOW WARNINGS Syntax.
IF EXISTS prevents MySQL from throwing an error, which is nice, but it causes a warning if the table does not exist. There is not an option to suppress this warning.

Can you modify an existing mysql trigger after it has been created?

In mysql I can create a trigger, and then show information about it like this:
mysql> show triggers like 'fooTrigger';
This command gives output that looks an awful lot like a select statement, with a row showing the matching trigger. Is it possible to update a column on the row it shows me?
For example, one column is named Statement, and it defines what happens when the trigger is activated. Is it possible to change the Statement field for fooTrigger so the trigger does something different? Or do I need to drop and re-create the trigger?
As of MySQL 5.5, you must drop and re-create the trigger.
It is not possible to update the Statement column without dropping the trigger.
Documentation: CREATE TRIGGER DROP TRIGGER
You may also access information about triggers using the INFORMATION_SCHEMA tables:
SELECT * FROM INFORMATION_SCHEMA.TRIGGERS
But, as these tables are actually views, you can't use UPDATE on them.
It's just a more convenient way to access and manipulate the information than using SHOW TRIGGERS.
Documentation: INFORMATION_SCHEMA.TRIGGERS
You may require, on Windows OS, Connector/Net Visual Studio Integration to view and edit existing database object. Limitation is that you can only edit trigger body within For each row ... loop.
Otherwise only option one has is drop and re create the trigger.
But make sure before dropping a trigger that the table associated with a trigger is locked and
and unlocked after trigger is re-created.
As #Jocelyn mentioned you can't alter the trigger. But if you're using MySql Workbench it will allow you to alter the trigger. Just right click on your table name and click Alter table option from there you can pick Trigger option and alter it. Although you cannot perform it from query.
Table Name --> Alter Table --> Triggers.

Drop table, then cannot recreate table with the same name

I first drop a table in SQL Server 2008 (after that it shows the message that the command was executed sucessfully).
I then tried to create a table with the same name, and it showed me an error.
After closing the SSMS window and re opening it it tried to create the table with the same name again and it succeeded.
What is going on?
You can't drop and create the same table in the same batch in sql server
see MSDN
Their examples use GO to break up the two commands. Semi colon might work,
Drop Table ...;
Create Table ,,,;
as might
Begin Transaction
Drop Table...
Commit Transaction
Create Table
Or of course splitting it up into two commands, which is what GO does in SQL server manager's query window.
If you do split it up, it might be wise to check whether the table exists before trying to drop it, and that it doesn't before trying to create it.