How to create mysql event inside a procedure or trigger? - mysql

recently i've been searching for a solution to the following situation:
I have mysql table with structure:
CREATE TABLE IF NOT EXISTS `battles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`begindate` datetime NOT NULL,
`enddate` datetime NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
Every battle has begindate and enddate. Begindate is datetime of insert and usually enddate is three days later.
I would like to create a mysql event that stops the battle (sets active = 0) at the battle enddate. And i would like this event to be created on insert trigger in the battles table.
There is an related issue with very few answers (here).
They advise:
You should be able to do it using a trigger and the event scheduler:
create a trigger on the table that is fired on every update / insert
this trigger creates a scheduled event that occurs at the datetime of the row and updates >your second table
I've tried to create such a query but with no success.
DELIMITER |
DROP TRIGGER IF EXISTS battle_create_end|
CREATE TRIGGER battle_create_end AFTER INSERT ON battles
FOR EACH ROW BEGIN
CREATE EVENT IF NOT EXISTS CONCAT('battle_end_',NEW.id)
ON SCHEDULE AT NEW.enddate
DO
UPDATE battles SET battles.active = 0 WHERE battles.id = NEW.id;
END|
DELIMITER ;
The error i get is
1576 - Recursion of EVENT DDL statements is forbidden when body is present
I've tried with different delimiters in the for each row structure with no success either.
If someone can help, please advise.
BR,
Ilko

Sorry brother but from what I have been reading what you are proposing is not possible. I don't think you can create an event with a trigger. Which is a bummer because it would be useful for me as well.
It would however be easier to create the event when the row for each battle is created. Hear is an example of some code I found from a guy explaining how events work.
<?php
// establish database connection and filter incoming data
// ...
// insert blog post with pending status, get id assigned to post
$query = "INSERT INTO blog_posts (id, title, post_text, status)
VALUES (NULL, :title, :postText, 'pending')";
$stm = $db->prepare($query);
$stm->execute(array(":title" => $title, ":postText" => $text));
$id = $db->lastInsertId();
// is this a future post?
if (isset($_POST["schedule"], $_POST["time"])) {
$scheduleDate = strtotime($_POST["time"]);
$query = "CREATE EVENT publish_:id
ON SCHEDULE AT FROM_UNIXTIME(:scheduleDate)
DO
BEGIN
UPDATE blog_posts SET status = 'published' WHERE id = :id;
END";
$stm = $db->prepare($query);
$stm->execute(array(":id" => $id, ":scheduleDate" => $scheduleDate));
}
// this is not a future post, publish now
else {
$query = "UPDATE blog_posts SET status = 'published' WHERE id = :id";
$stm = $db->prepare($query);
$stm->execute(array(":id" => $id));
}
So basically create the event when you add a battle to the table.

Related

Can anyone help me out how to perform MySQL trigger logic from existing MS SQL trigger Logic

I have two tables one is Master table where the Daily data keeps loading. Other one is Audit Table which tracks whenever there is an update (single/multiple columns updates) happened on Master Table. Below is the logic used for MS SQL
/*** Mastertable creation **/
CREATE TABLE [dbo].[Master](
[ID] [uniqueidentifier] primary key NOT NULL DEFAULT (newid()),
[Name] [varchar](100) ,
[Status] [varchar](10),
[Dept] [varchar](10) )
/** Inserting Data to Master table ***/
Insert into [dbo].[Master] ([Name],[Status],[Dept]) Values
('AAAA', 'Open','EC'),
('BBBB', 'Closed','CS')
/** Audit Table creation ***/
CREATE TABLE [dbo].[Orders_Audit](
[Id] [uniqueidentifier] NOT NULL,
[ColName] [varchar](50),
[OldValue] [varchar](200),
[NewValue] [varchar](200),
[ModifiedAt] [datetime],
[ModifiedBy] [varchar](50) )
Go
/*** Trigger used based on columns for any updates in Master Table***/
Create TRIGGER [dbo].[Tr_Master]
ON [dbo].[Master]
FOR UPDATE
AS
BEGIN
Declare #action varchar(50)
IF UPDATE([Status])
BEGIN
SET #Action = 'Status'
Insert into [dbo].[Orders_Audit] (Id,ColName,OldValue,NewValue,ModifiedAt,ModifiedBy)
select i.Id,#action ,d.[Status] ,i.[Status] ,getdate() ,SUSER_SNAME()
from inserted i,
deleted d where i.Id = d.Id
END
IF UPDATE([Dept])
BEGIN
SET #Action = 'Dept'
Insert into [dbo].[Orders_Audit] (Id,ColName,OldValue,NewValue,ModifiedAt,ModifiedBy)
select i.Id,#action ,d.[Dept] ,i.[Dept] ,getdate() ,SUSER_SNAME()
from inserted i,
deleted d where i.Id = d.Id
END
End
GO
Need to implement same logic in MySQL
Thanks in Advance!!
CREATE TRIGGER trigger_name
AFTER UPDATE ON Master
FOR EACH ROW
BEGIN
IF NOT (OLD.Status <=> NEW.Status) THEN
INSERT INTO Orders_Audit (Id, ColName, OldValue, NewValue, ModifiedAt, ModifiedBy)
SELECT NEW.Id, 'Status', OLD.Status, NEW.Status, NOW(), CURRENT_USER();
END IF;
IF NOT (OLD.Dept <=> NEW.Dept) THEN
INSERT INTO Orders_Audit (Id, ColName, OldValue, NewValue, ModifiedAt, ModifiedBy)
SELECT NEW.Id, 'Dept', OLD.Dept, NEW.Dept, NOW(), CURRENT_USER();
END IF;
END
IF NOT (OLD.column <=> NEW.column) checks that the column value was changed. This expression is NULL-safe (rather than IF OLD.column <> NEW.column) - i.e. it correctly checks the result when one of the values or both of them are NULL.
PS. CURRENT_USER() returns the account name which was used for authentication. If you need the username provided by the client during authentication then use USER() function instead. Example: user may provide 'john'#'1.2.3.4' (and USER() returns this) but the account used may be 'john'#'%' (and CURRENT_USER() returns this). For stored objects/views CURRENT_USER() may return not invoker but definer account (depends on SECURITY attribute).

Changing the value of a field from a table when another is changed using triggers

Good morning everyone.
I have a table like this in mysql:
CREATE TABLE NC
(
ID INTEGER AUTO_INCREMENT NOT null,
reportingDate DATE,
closingDate DATE,
State VARCHAR(20),
PRIMARY KEY(CodNC)
)
What I need is to automatically changing the value of the field "ClosingDate" up to today everytime the value of the field "State" is changed with "Closed" using TRIGGERS.
Thanks
This looks like a simple before update trigger:
delimiter //
create trigger trg_nc_before_state_update
before update on nc
for each row
begin
if new.state = 'Closed' and not old.state <=> 'Closed' then
set new.closingdate = current_date;
end if;
end
//
delimiter ;

time difference calculation in sql

Hello I'm trying to create a trigger(or more) in order to calculate the time difference in a mysql table (I'm using mysql 5.7.21).
The table I have is this :
CREATE TABLE people(
username VARCHAR(255) NOT NULL,
state VARCHAR(255) NOT NULL DEFAULT 'not active',
PRIMARY KEY(username)
);
Some explanation about the table : The username column is self-explanatory and the state column get only 1 out of 3 values : 'active', 'not active','working' .
Specifically a person can change from 'active' to 'not active'/'working' and vice-versa but cannot change from 'not active' to 'working' or from 'working' to 'not active'.
What I want to do is to keep track of how much time has a person been active/working for.
Now my idea is have a table like this :
Create table Time(
username VARCHAR(255) NOT NULL,
timestarted TIME,
timeended TIME,
timeworking TIME,
FOREIGN KEY (username) REFERENCES people(username)
);
My first guess was to use the CURRENT_TIME() function to keep track of state using triggers.
What I did is :
Delimiter $$
CREATE TRIGGER time_calculation
BEFORE Update
ON people
FOR EACH ROW BEGIN
DECLARE #times time;
DECLARE #timee time;
DECLARE #timet time;
IF OLD.state = 'not active' THEN
UPDATE Time SET timestart = CURRENT_TIME() WHERE username = new.username;
END IF;
IF NEW.state = 'not active' THEN
set #times = (select timestarted from time where username = new.username);
set #timee = (select timeended from time where username = new.username);
set #timet = (select timeworking from time where username = new.username);
UPDATE Time SET timeend = CURRENT_TIME(),timeworking = (TIMEDIFF(times,timee)+timet) WHERE username = new.username;
END IF;
END$$
According to this trigger. Every time someone switches from 'not active' to 'active' the Time table will get the current time of that switch as timestart.When someone switches to 'not active' the Time table will get the current time as timeend and it will add the difference between timestart and timeend to timeworking. The trigger shows the following error :
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE #times time;
DECLARE #timee time;
DECLARE #timet time;
BEGIN
IF OLD.state =' at line 5
Don't know what's wrong with it. Any ideas?
Well I found a way to solve this problem although it wasn't as I expected it. I made some changes in the table structure as follows :
Create table people (
username VARCHAR(255) NOT NULL,
Primary Key (username)
);
Create table characteristics (
username VARCHAR(255) NOT NULL,
state VARCHAR(25) NOT NULL DEFAULT 'not active',
timestart TIME,
timestop TIME,
timetotal TIME NOT NULL DEFAULT '00:00:00',
FOREIGN KEY(username) REFERENCES people(username)
);
As for the trigger to get the time difference it's as follows :
Delimiter $$
CREATE TRIGGER time_calculation
BEFORE Update
ON characteristics
FOR EACH ROW BEGIN
IF OLD.state = 'not active' && NEW.state != 'not active' THEN
SET NEW.timestart = CURRENT_TIME();
END IF;
IF NEW.state = 'not active' && OLD.state != 'not active' THEN
SET NEW.timestop = CURRENT_TIME();
SET NEW.timetotal = ADDTIME(OLD.timetotal,TIMEDIFF(NEW.timestop, OLD.timestart));
END IF;
END$$
Delimiter ;
Hope this helps anyone having the same problem with me !

MySQL - Update a column after information get's inserted

I have a table in MySql table like the following
row_timestamp timestamp
, row_id int(11) auto_increment
, mrn char(17)
, patients_last_name varchar(50)
, patients_first_name varchar(50)
, ssn char(4) default '0000'
, visit_key NULL
upon the insertion of a record, I'd like visit_key to bet set to visit_key = concat(mrn, row_id) I was trying to accomplish this with a before insert trigger to no avail, I kept getting that the mrn column was not in the field select list.
Update
I tried the following, which seems not to work because the auto_increment has not yet incremented:
set new.visit_key = concat(new.mrn, new.row_id)
I also tried
set new.visit_key = concat(new.mrn, max(row_id)+1)
I am thinking of the trigger to sort of act like a calculated field in MS Access, is this reasonable? Thoughts? Would it not be possible to do since the visit_key would technically be NULL and you cannot update a new value?
UPDATE
I used the following code that I adapted from this question here
DELIMITER //
CREATE TRIGGER vkt AFTER INSERT ON demographic_information
FOR EACH ROW
BEGIN
UPDATE `demographic_information` SET visit_key_test = concat(new.mrn, mew.row_id) WHERE row_id = NEW.row_id;
END;
//
DELIMITER ;
and got the following error message:
INSERT INTO `manchuco_nys_trauma`.`demographic_information` (
`row_timestamp` ,
`row_id` ,
`mrn` ,
`patients_last_name` ,
`patients_first_name` ,
`ssn` ,
`visit_id` ,
`visit_key_test`
)
VALUES (
CURRENT_TIMESTAMP , NULL , '123456', 'Sanderson', 'Steven', '1234', '12345670', NULL
)
MySQL said: Documentation
#1442 - Can't update table 'demographic_information' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Thank you,
What you observe seems normal: since you're using BEFORE INSERT the id value doen't exist yet.
And the same applies for your try with concat(new.mrn, **new**.row_id): NEW has no sense at the moment.
So I suggest you use AFTER INSERT instead.
Try selecting the auto increment value inside the trigger:
CREATE TRIGGER trigger_name AFTER INSERT ON yourTable FOR EACH ROW
BEGIN
DECLARE next_id integer;
SET next_id = (SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA='yourDB' AND TABLE_NAME='yourTable');
SET new.visit_key = CONCAT(new.mrn, next_id);
END
I discovered this approach in this SO article.

MySql - ON DUPLICATE KEY INSERT

I understand that there exists INSERT IGNORE and INSERT ... ON DUPLICATE KEY UPDATE. However, when there is a duplicate key, I'd like to do a INSERT to a temporary table to keep a record of the unique key that has been violated, so that I can output it to the user.
Is there any way I can do a ON DUPLICATE INSERT? If it helps, I'm trying to do a bulk insert.
With ON DUPLICATE KEY UPDATE, you cannot insert into another table - nor is there an alternative function available.
Two custom/alternative ways you can accomplish this:
Using a stored procedure as outlined in the accepted answer to this question: MySQL ON DUPLICATE KEY insert into an audit or log table
Creating a trigger that logged every INSERT for your table into another table and querying the table full of "logs" for any duplicates.
Something similar to this should work:
CREATE TABLE insert_logs (
id int not null
);
delimiter |
CREATE TRIGGER insert_logs_trigger BEFORE INSERT ON your_table
FOR EACH ROW BEGIN
INSERT INTO insert_logs SET id = NEW.id;
END;
|
To get a list of the duplicates in the table, you could us:
SELECT id FROM insert_logs HAVING COUNT(id) > 1 GROUP BY id;
Maybe this could be helpful:
$time = time();
$countme = 1;
while ($countme > 0) {
$stmt = $mysqli->prepare("INSERT INTO loads (dte,filecode,id,acct,nmbr) VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE dte = dte");
$stmt->bind_param("sssss", $time, $filecode, $id, $acct, $number);
$stmt->execute();
$countme++;
if ($stmt->affected_rows === 1) {
$countme = 0; // all is good
} else {
$time = $time + 1;
}
if ($countme === 4) {
exit;
}
}