MySQL Trigger after insert and add timestamp when data changed - mysql

This is my perl sample code and what i needed is add a timestamp into columns when data changed(updated).
use strict;
use DBI;
use POSIX qw(strftime);
my $datestring = strftime "%Y-%m-%d %H:%M:%S",localtime;
my $dbh = DBI->("dbi:mysql:dbname=perldb","root","111111",{RaiseError=>1})
or die DBI::errstr();
my $mac1='mac1';
my $ip1='ip1';
my $mac2='mac2';
my $ip2='ip2';
$dbh->do("DROP TABLE IF EXISTS Test1");
$dbh->do("CREATE TABLE Test1(Id INT PRIMARY KEY AUTO_INCREMENT,IP TEXT,MAC TEXT,TIME DATETIME,PrevTime DATETIME) ENGINE=InnoDB");
$dbh->do("CREATE Trigger trigger1 AFTER INSERT ON Test1
FOR EACH ROW
BEGIN
IF OLD.MAC!=NEW.MAC
THEN SET NEW.TIME='$datestring';
END IF;
END;")
$dbh->do("INSERT INTO Test1(IP,MAC) VALUES('$ip1','$mac1') ON DUPLICATE KEY UPDATE IP=VALUE(IP)");
$dbh->do("INSERT INTO Test1(IP,MAC) VALUES('$ip2','$mac2') ON DUPLICATE KEY UPDATE IP=VALUE(IP)");
$dbh->disconnect();
The goal I want to reach is run this code once then modify $mac1 to 'mac3'.
So that it will trigger SET timestamp because the data was changed.
Also SET old one timestamp to PrevTIME, but OLD for INSERT.
Result I need maybe like this:
+----+------+------+---------------------+----------+
| Id | IP | MAC | TIME | PrevTime |
+----+------+------+---------------------+----------+
| 1 | ip1 | mac1 | 2015-03-03 12:34:56 | NULL |
| 2 | ip2 | mac2 | 2015-03-03 12:34:56 | NULL |
+----+------+------+---------------------+----------+
Then
+----+------+------+---------------------+---------------------+
| Id | IP | MAC | TIME | PrevTime |
+----+------+------+---------------------+---------------------+
| 1 | ip1 | mac3 | 2015-03-03 12:40:00 | 2015-03-03 12:34:56 |
| 2 | ip2 | mac2 | 2015-03-03 12:34:56 | NULL |
+----+------+------+---------------------+---------------------+
Anyidea? Please help me figure out,THANK YOU.
-------------------------------SOLUTION---------------------------------------
use strict;
use DBI;
use POSIX qw(strftime);
my $datestring = strftime "%Y-%m-%d %H:%M:%S",localtime;
my $dbh = DBI->("dbi:mysql:dbname=perldb","root","111111",{RaiseError=>1})
or die DBI::errstr();
my $mac1='mac1';
my $ip1='ip1';
my $mac2='mac2';
my $ip2='ip2';
$dbh->do("CREATE TABLE IF NOT EXISTS Test1(Id INT PRIMARY KEY AUTO_INCREMENT,IP TEXT,MAC TEXT,TIME DATETIME,PrevTime DATETIME,UNIQUE(IP)) ENGINE=InnoDB");
$dbh->do("CREATE Trigger trigger1 BEFORE INSERT ON Test1
FOR EACH ROW
BEGIN
SET NEW.TIME='$datestring';
END;")
$dbh->do("CREATE Trigger trigger2 BEFORE UPDATE ON Test1
FOR EACH ROW
BEGIN
IF OLD.MAC <> NEW.MAC
THEN
SET NEW.PrevTIME=OLD.TIME;
SET NEW.TIME='$datestring';
END IF;
END;")
$dbh->do("INSERT INTO Test1(IP,MAC) VALUES('$ip1','$mac1') ON DUPLICATE KEY UPDATE IP=VALUE(MAC)");
$dbh->do("INSERT INTO Test1(IP,MAC) VALUES('$ip2','$mac2') ON DUPLICATE KEY UPDATE IP=VALUE(MAC)");
$dbh->disconnect();

You actually need 2 triggers one before insert and one before update. The before insert will set the TIME to now(), while the before update will check the old and new values of mac and set the PrevTime to old TIME and TIME to now()
Here are the triggers, you can have them in your code
delimiter //
create trigger trigger1 before insert on Test1
for each row
begin
set new.TIME = now();
end ; //
delimiter //
create trigger trigger2 before update on Test1
for each row
begin
if old.MAC <> new.MAC then
set new.PrevTime = old.TIME ;
set new.TIME = now();
end if;
end ;//

Triggers are event specific.
You are using an INSERT and hence AFTER or BEFORE Trigger works defined for INSERT events.
You actually need a BEFORE UPDATE trigger.
Add a similar trigger for BEFORE TRIGGER
Example:
CREATE TRIGGER bu_on_Test BEFORE UPDATE ON Test1
FOR EACH ROW
BEGIN
IF OLD.MAC <> NEW.MAC THEN
SET NEW.TIME='$datestring';
END IF;
END;
But note that Triggers won't take dynamic input parameters like '$datestring'.
If such a value is set in your scripting language, that is for lifetime of trigger definition and is not going to change during its execution.

Related

How to make triggers for delete and adding with if statement MySQL?

have two table's Queue (appointment_id, actual_time) Queue_Summary (date, doctor_id, num_of_patients)
The first is all the queues there are and the second is how many queues for each doctor on a certain date. I need to build a trigger that updates the num_of_patients, every time in Queue that a queue is added I need to add to a doctor num_of_patients on that date. Also when removing.
I have just counted the number of queues given a doctor_id and date, made it into two triggers.
But the only problem I have is where do I place the if statement that checks if this date is on Queue_Summary and if not adds it.
(P.S - Im not 100% on thoes also as my database is a bit off and does tons of problems, if there are any problem in thoes statments I'll be more them happy to know)
delimiter //
CREATE TRIGGER update_queue_summary
AFTER DELETE ON queue
FOR EACH ROW
BEGIN
update queue_summary as qs set num_of_patient = (
select count(appointment_id)
from queue as q join appointment as a on appointment_id
where a.doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date())
group by appointment_id
) where doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date());
END;//
delimiter ;
delimiter //
CREATE TRIGGER update_queue_summary
AFTER insert ON queue
FOR EACH ROW
BEGIN
update queue_summary as qs set num_of_patient = (
select count(appointment_id)
from queue as q join appointment as a on appointment_id
where a.doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date())
group by appointment_id
) where doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date());
END;//
delimiter ;
You should carry out an existence test in your trigger. For example
drop table if exists queue,queue_summary;
create table queue (appointment_id int auto_increment primary key, doctor_id int,actual_time datetime);
create table Queue_Summary (date date, doctor_id int, num_of_patients int);
delimiter $$
create trigger ut after insert on queue
for each row
begin
if not exists (select 1 from queue_summary where date = date(new.actual_time) and doctor_id = new.doctor_id) then
insert into queue_summary values(date(new.actual_time),new.doctor_id,1);
else
update queue_summary
set num_of_patients = num_of_patients + 1
where date = date(new.actual_time) and doctor_id = new.doctor_id;
end if;
end $$
delimiter ;
insert into queue (doctor_id,actual_time) values(1,'2020-05-03 09:00'),(1,'2020-05-03 09:30');
select * from queue;
select * from queue_summary;
MariaDB [sandbox]> select * from queue;
+----------------+-----------+---------------------+
| appointment_id | doctor_id | actual_time |
+----------------+-----------+---------------------+
| 1 | 1 | 2020-05-03 09:00:00 |
| 2 | 1 | 2020-05-03 09:30:00 |
+----------------+-----------+---------------------+
2 rows in set (0.001 sec)
MariaDB [sandbox]> select * from queue_summary;
+------------+-----------+-----------------+
| date | doctor_id | num_of_patients |
+------------+-----------+-----------------+
| 2020-05-03 | 1 | 2 |
+------------+-----------+-----------------+
1 row in set (0.001 sec)
And a delete trigger is similar but simpler
delimiter $$
create trigger dt after delete on queue
for each row
begin
if exists (select 1 from queue_summary where date = date(OLD.actual_time) and doctor_id = old.doctor_id) then
update queue_summary
set num_of_patients = num_of_patients - 1
where date = date(old.actual_time) and doctor_id = old.doctor_id;
end if;
end $$
delimiter ;
The existence check is entirely cosmetic since a delete won't complain if there is nothing to delete.

Trigger "AFTER INSERT" doesn't work, after insertion if I Add values in tables?

Purpose of trigger:
I should +add some number 50 to that user to table money where in table paym both columns table1 and table2 are not empty.
For example: User 'John' has both columns not empty and to him added 50 in table money.
Example in table below:
table: paym
ID username table1 Table2
+-------+-------------+-------------+-----------+
| 1 | John | Value | Value |
+-------+-------------+-------------+-----------+
| 2 | Alex | Null | Null |
+-------+-------------+-------------+-----------+
Table: money
ID username total_money
+-------+-------------+-------------+
| 1 | John | 50 |
+-------+-------------+-------------+
| 2 | Alex | 0 |
+-------+-------------+-------------+
Trigger below, works perfectly only when we insert all tables at one time. But it doesn't work if you insert only username two tables empty and after insertion, if you add values to empty tables table1 and table2 triggers not works at this point! Can we solve this problem???
Trigger should work even if we add value to the table After insertion!
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER INSERT ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL) THEN
UPDATE money SET total_money = total_money + 50 WHERE username = NEW.username;
END IF;
END;
$$
DELIMITER;
Not that trigger. It is an insert trigger, so it doesn't get called for an update.
If you want an update trigger, then define one:
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER UPDATE ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL) THEN
UPDATE money m
SET total_money = total_money + 50
WHERE m.username = NEW.username;
END IF;
END;
$$
DELIMITER;
This may not do exactly what you want. For instance, you might only want to add 50 when the previous values are both NULL:
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER UPDATE ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL AND
OLD.table1 IS NULL AND old.table2 IS NULL) THEN
UPDATE money m
SET total_money = total_money + 50
WHERE m.username = NEW.username;
END IF;
END;
$$
DELIMITER;

Mysql trigger when on update reserved cloumn sub capacity if statements

I want to set check class capacity if will be full class should be
confirm. When I update reserved it give error. Please help. Thank you.
CREATE TRIGGER `control_class_capacity`
AFTER UPDATE ON `learningcenter_class`
FOR EACH ROW BEGIN
IF NEW.capacity - NEW.reserved = 0 THEN BEGIN
UPDATE learningcenter_class SET isconfirm = 1 WHERE class_id = NEW.class_id;
END; END IF;
END
Assuming your class_id is unique you could change the trigger to a before trigger and set NEW.ISCONFIRM. BTW if statements in MYSQL do not require begin and end statements.
drop table if exists t;
create table t(class_id int ,capacity int, reserved int, isconfirm int);
insert into t values (1,1,0,0) , (2,1,0,0);
drop trigger if exists `control_class_capacity`;
delimiter $$
CREATE TRIGGER `control_class_capacity`
before UPDATE ON t
FOR EACH ROW BEGIN
IF NEW.capacity - NEW.reserved = 0 THEN
SET new.isconfirm = 1;
END IF;
END $$
delimiter ;
update t set reserved = 1 where class_id = 1;
select * from t;
+----------+----------+----------+-----------+
| class_id | capacity | reserved | isconfirm |
+----------+----------+----------+-----------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 0 | 0 |
+----------+----------+----------+-----------+
2 rows in set (0.00 sec)

Trigger to invalidate cache after update

I'm trying to write a trigger to invalidate the word index for my story database. However I can't seem to figure out how to stop the trigger from firing again during the indexing operation. I know I need to place an if statement to stop the update, but I can't seem to figure out what it should look like.
CREATE TRIGGER trMarkStoryForReindex BEFORE UPDATE ON Chapters
FOR EACH ROW BEGIN
-- any update to any chapter invalidates the index for the whole story
-- we could just periodically flush the story index, but this way is
-- better.
SET New.isIndexed = FALSE;
-- delete the index for that story
-- It will get rebuilt in at most 15 minutes
DELETE FROM freq WHERE storyid = NEW.StoryId;
END;
I basically want the trigger to fire only when isIndexed is has not been set in the update statement causing the trigger.
My data model looks like so:
Chapters
id
isIndexed
StoryId
Freq
word
storyid
Here's my proposal for solution. I've tested this on SQL fiddle, and it seems to work:
-- Database setup
create table chapters (
id int unsigned not null auto_increment primary key,
isIndexed boolean default false,
storyId int not null,
index idx_storyId(storyId)
);
create table freq (
word varchar(50),
storyId int not null,
index idx_storyId(storyId)
);
delimiter //
create trigger bi_chapters before update on chapters
for each row
begin
if new.isIndexed = false then
delete from freq where storyId = new.storyId;
end if;
end //
delimiter ;
insert into freq(word, storyId)
values ('one', 1), ('two', 1), ('three', 2);
insert into chapters(isIndexed, storyId)
values (true, 1), (true, 2);
When you select the values from freq (before updating chapters) you get this:
select * from chapters;
| id | isIndexed | storyId |
|----|-----------|---------|
| 1 | false | 1 |
| 2 | true | 2 |
select * from freq;
| word | storyId |
|-------|---------|
| one | 1 |
| two | 1 |
| three | 2 |
Now, do an update to chapters and select from freq again:
update chapters
set isIndexed = false
where storyId = 1;
select * from freq;
| word | storyId |
|-------|---------|
| three | 2 |
The only modification I did is that if block that checks if the new row is updated to false. If I've understood your question correctly, this would do what you need.
SQL fiddle example

SQL IF - ELSE Statement

I have a table like this :
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| ID | bigint(20) | NO | PRI | NULL | |
| view | bigint(20) | NO | | NULL | |
+-------+------------+------+-----+---------+-------+
Is it possible to do this with SQL's IF-ELSE statement ?
Check if there is ID=1 row in table
If there is , increase view column by 1 .
If there isn't, insert new row to table with ID=1
It should be something like this :
IF((SELECT COUNT(ID) FROM wp_viewcount WHERE ID=1) == 0)
BEGIN
INSERT INTO wp_viewcount VALUES (1,1)
END
ELSE
BEGIN
UPDATE wp_viewcount SET view=view+1 WHERE ID=1
END
The following SQL statement will result in the IF - ELSE logic you want, by using the on duplicate key syntax.
insert into wp_viewcount values(1,1) on duplicate key update view=view+1;
You can only use MySQL's if in a stored procedure. For example:
DELIMITER //
CREATE PROCEDURE `test_procedure` (IN wp_id INT)
BEGIN
IF( (SELECT COUNT(*) FROM wp_viewcount WHERE id = wp_id)<1) THEN
INSERT INTO wp_viewcount(id,view) VALUES (wp_id,1);
ELSE
UPDATE wp_viewcount SET view=view+1 WHERE ID=wp_id;
END IF;
END //
Given your use case, you might be better served by MySQL's INSERT ... ON DUPLICATE KEY UPDATE.
Why not use
if not exists (select * from wp_viewcount where id = 1)
begin
--insert logic
end
else
begin
--update logic
end