MySQL AFTER UPDATE in a specific column UPDATE timestamp in same row - mysql

I want to update the timestamp 'lastpageview_at', when the pageviews increases. I think I'm close but I always get a syntax error, does anybody know why or have an other solution?
My trigger:
CREATE TRIGGER Update_lastpageview BEFORE UPDATE ON shortlinks
FOR EACH ROW BEGIN
IF OLD.pageviews <=> NEW.pageviews THEN
SET NEW.lastpageview_at = CURRENT_TIMESTAMP();
END IF;
END;
Here is my table:
CREATE TABLE `shortlinks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`shortlink_id` varchar(40) NOT NULL DEFAULT '',
`pageviews` int(11) unsigned DEFAULT NULL,
`lastpageview_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `shortlink` (`shortlink`)
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8;

inequality operator is either != or <> not <=>
delimiter $$
CREATE TRIGGER Update_lastpageview BEFORE UPDATE ON shortlinks
FOR EACH ROW BEGIN
IF OLD.pageviews <> NEW.pageviews THEN
SET NEW.lastpageview_at = NOW();
END IF;
END;$$

Related

my trigger error in mysql, hen help to fix

I can't understand why my trigger doesn't work.
first table:
CREATE TABLE `Payment` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idPaymentMethod` int(20) DEFAULT NULL,
`createAt` timestamp NOT NULL DEFAULT current_timestamp(),
`updateAt` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE current_timestamp(),
`actived` tinyint(1) NOT NULL DEFAULT 1,
`numberInvoices` int(11) DEFAULT NULL,
`preferentialPaymentDay` int(11) DEFAULT NULL,
`invoicesFrequency` bigint(20) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
second table:
CREATE TABLE `PaymentHistory` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`idPaymentMethod` int(20) DEFAULT NULL,
`idPayment` int(20) DEFAULT NULL,
`createAt` timestamp NOT NULL DEFAULT current_timestamp(),
`updateAt` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE current_timestamp(),
`actived` tinyint(1) NOT NULL DEFAULT 1,
`numberInvoices` int(11) DEFAULT NULL,
`preferentialPaymentDay` int(11) DEFAULT NULL,
`invoicesFrequency` bigint(20) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
my trigger:
DELIMITER $$
CREATE
TRIGGER `update_history` AFTER
UPDATE
ON
`Payment`
FOR EACH ROW BEGIN
UPDATE
`PaymentHistory`
SET
id = OLD.id,
idPaymentMethod = old.idPaymentMethod,
createAt = old.createAt,
updateAt = old.updateAt,
actived = old.actived,
numberInvoices = old.numberInvoices
END$$
I get a lot of errors when I try to fix something.
Errors I get:
SQL Error [1064] [42000]: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'END$$' at line 1
SQL Error [1054] [42S22]: Unknown column 'OLD.id' in 'field list'
I am really lost.
I need all the updated data in the "Payment" table to be inserted or updated into the "PaymentHistory" table
Plase, i need a help.
You need to finish each command with a semicolon
DELIMITER $$
CREATE
TRIGGER `update_history` AFTER
UPDATE
ON
`Payment`
FOR EACH ROW BEGIN
UPDATE
`PaymentHistory`
SET
id = OLD.id,
idPaymentMethod = old.idPaymentMethod,
createAt = old.createAt,
updateAt = old.updateAt,
actived = old.actived,
numberInvoices = old.numberInvoices;
END$$
DELIMITER ;
See example
first, thanks to #nbk
i solved with yours help
i change de "after" to "before" and add the ";"
see;
TRIGGER `update_history` BEFORE
UPDATE
ON
`Payment`
FOR EACH ROW BEGIN
UPDATE
`PaymentHistory`
SET
idPayment = old.id
, idPaymentMethod = old.idPaymentMethod
, createAt = old.createAt
, updateAt = old.updateAt
, actived = old.actived
, numberInvoices = old.numberInvoices;
END

How to create trigger for broken cars using IF statement

I want to create a trigger that will not allow to rent a car if it is currently being repaired. Im quite new in triggers... could anyone shed some light on this aspect of triggers? My assumptions would be that it would something like...
DELIMITER $$
CREATE TRIGGER `inspections_const` BEFORE UPDATE ON `inspections` FOR EACH ROW BEGIN
SET NEW.booking_id = IF.repair_complete = 'No'
THEN 'Allow booking'
ELSE 'Do not allow'
END;
END
$$
DELIMITER ;
Table is
CREATE TABLE `inspections` (
`inspection_id` int(10) NOT NULL,
`inspection_date` date NOT NULL,
`vehicle_id` int(10) NOT NULL,
`problem` varchar(50) NOT NULL,
`repair_complete` enum('Yes','No') NOT NULL,
`mechanic_id` int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `bookings` (
`booking_id` int(50) NOT NULL,
`booking_date` date NOT NULL,
`start_date` date NOT NULL,
`end_date` date NOT NULL,
`invoice_no` int(10) NOT NULL,
`chauffeur_id` int(10) DEFAULT NULL,
`vehicle_id` int(10) NOT NULL,
`customer_id` int(50) NOT NULL,
`chauffeur_req` enum('Yes','No') NOT NULL,
`special_instructions` varchar(255) NOT NULL,
`TheDuration` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I didn't tested it so it might have a missing condition or something like that. But it should help you on the correct path
Query
DELIMITER $$
CREATE TRIGGER `check_repair` BEFORE INSERT ON `bookings` FOR EACH ROW BEGIN
# We need to save the "count"
DECLARE inspections_count INT DEFAULT 0;
# Check if where is a repair going which matches the vehicle_id
SELECT
1 INTO inspections_count # store the "count" into the variable.
FROM inspections
WHERE
inspections.vehicle_id = NEW.vehicle_id
AND
repair_complete = 'No'
ORDER BY
inspections.start_date DESC
LIMIT 1;
# if there is a "count" stop the insert.
IF inspections_count = 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'vehicle is in repair';
END IF;
END
$$
DELIMITER ;

mySQL trigger fails on UPDATE statement

I have two tables and one trigger. The trigger fails on the UPDATE on table sensors. I have tested the trigger updating another table and that just works fine so I expect this to be a problem with locking on sensors. I'm certainly not an expert on mySQL and I did some searching. I have tried to add SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; before the first SELECT in the trigger but that did not make any difference.
Table measurements:
CREATE TABLE `measurements` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sensorid` int(16) DEFAULT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`distance` int(11) NOT NULL,
`temperature` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26727 DEFAULT CHARSET=latin1;
Table sensors:
CREATE TABLE `sensors` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` char(32) DEFAULT '',
`zeropoint` int(11) unsigned DEFAULT NULL,
`threshold` int(11) unsigned DEFAULT NULL,
`hysteresis` int(11) DEFAULT NULL,
`status` enum('normal','alarm') DEFAULT 'normal',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
Trigger raise alarm:
CREATE TRIGGER `raise alarm` BEFORE INSERT ON `measurements`
FOR EACH ROW
begin
declare zp integer;
declare st char(32);
select zeropoint into zp from sensors where id = new.sensorid;
select status into st from sensors where id = new.sensorid;
if new.distance > zp then
if st = 'normal' then
update sensors set status = 'alarm' where id = new.sensorid;
end if;
end if;
end;
There is something in the documentation that you might be interested in:
https://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html
In a BEFORE trigger, the NEW value for an AUTO_INCREMENT column is 0,
not the sequence number that is generated automatically when the new
row actually is inserted.
It means, that all queries in your trigger are always looking for a record with id=0, since id column in measurement table is auto-increment.
In case there is no record id=0 in sensors table, then zp variable is null, and this condition: if new.distance > zp then is always false.

Using Auto-Increment value in MYSQL Before Insert Trigger?

The users table:
CREATE TABLE `users` (
`id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(45) DEFAULT NULL,
`username` varchar(16) DEFAULT NULL,
`salt` varchar(16) DEFAULT NULL,
`password` varchar(128) DEFAULT NULL,
`lastlogin` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`joined` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`loggedin` tinyint(1) unsigned NOT NULL DEFAULT '0',
`sessionkey` varchar(60) DEFAULT NULL,
`verifycode` varchar(16) DEFAULT NULL,
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`banned` tinyint(1) unsigned NOT NULL DEFAULT '0',
`locked` tinyint(1) unsigned NOT NULL DEFAULT '0',
`ip_address` varchar(45) DEFAULT NULL,
`failedattempts` tinyint(1) unsigned NOT NULL DEFAULT '0',
`unlocktime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
The user_records table:
CREATE TABLE `user_records` (
`id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`userid` int(8) unsigned DEFAULT NULL,
`action` varchar(100) DEFAULT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
The before insert trigger on the users table:
USE `gknet`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` TRIGGER `before_create_user` BEFORE INSERT ON `users` FOR EACH ROW BEGIN
INSERT INTO user_records (action, userid, timestamp)
VALUES ('CREATED', ID, NOW() );
END
Basically, my problem here is that on the trigger when I try to put in the id of the user that's automatically assigned by MySQL (PK, NN, Auto-Increment), it just puts in 0 for userid on the user_records table. How would I do it so it would select the id that the user is being assigned by SQL, and put it in as userid on the records entry (where the ID is right after 'CREATED')?
Also, if you see any other optimizations that could be made on the tables, feel free to let me know :D
OP's comment:
How would I do it before, thou?
You can find current auto_increment value that is to be assigned to a new record.
And use the same in the before trigger as a parent user id for user_records table.
You have to query information_schema.tables table to find the value.
Example:
use `gknet`;
delimiter $$
drop trigger if exists before_create_user; $$
create definer=`root`#`localhost` trigger `before_create_user`
before insert on `users`
for each row begin
declare fk_parent_user_id int default 0;
select auto_increment into fk_parent_user_id
from information_schema.tables
where table_name = 'users'
and table_schema = database();
insert into user_records ( action, userid, timestamp )
values ( 'created', fk_parent_user_id, now() );
end;
$$
delimiter ;
Observations:
As per mysql documentation on last_insert_id(),
"if you insert multiple rows using a single INSERT statement,
LAST_INSERT_ID() returns the value generated for the first inserted
row only."
hence, depending on last_insert_id() and auto_increment field values in batch inserts seems not reliable.
Change the trigger to after insert instead of before insert and use NEW to get the last inserted id
USE `gknet`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost`
TRIGGER `after_create_user` AFTER INSERT ON `users`
FOR EACH ROW
BEGIN
INSERT INTO user_records (action, userid, timestamp)
VALUES ('CREATED', NEW.ID, NOW() );
END; $$
PLEASE USE AFTER INSERT AND UPDATE
Do not make auto_increment any column you want to manipulate explicitly. That can confuse an engine and cause serious problems. If no column you have used for primary key are auto_increment you can do anything you want with them via triggers. Sure generated values will be rejected if they violate the mandatory uniqness of the primary key.
maybe this solution can
BEGIN
DECLARE id int;
SELECT MAX(table_id)
FROM table
INTO id;
IF id IS NULL THEN
SET NEW.column=(CONCAT('KTG',1));
ELSE
SET NEW.column=(CONCAT('KTG',id+1));
END IF;
END

creating a trigger - declare variable - Cant get my trigger to work

This trigger is designed to update 'field_csvfilepath_value' to match 'filepath' in the files table (some table details below). But I cant get it to work, please help.
delimiter $$
CREATE TRIGGER csv_filpath
AFTER INSERT ON content_type_importcsv for each row
begin
declare p varchar(80)
set p := (SELECT filepath FROM content_type_importcsv join files where NEW.content_type_importcsv.field_csv1_fid = files.fid)
set NEW.field_csvfilepath_value = p
end$$
delimiter ;
This trigger is generating the following error:
Error Code: 1064. 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 'set p := (SELECT filepath FROM content_type_importcsv join files where NEW.conte' at line 5
I'm using mysql workbench 5.2
delimiter $$
delimiter $$
CREATE TABLE `content_type_importcsv` (
`vid` int(10) unsigned NOT NULL DEFAULT '0',
`nid` int(10) unsigned NOT NULL DEFAULT '0',
`field_csv1_fid` int(11) DEFAULT NULL,
`field_csv1_list` tinyint(4) DEFAULT NULL,
`field_csv1_data` text,
`field_csvfilepath_value` longtext,
PRIMARY KEY (`vid`),
KEY `nid` (`nid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8$$
CREATE TABLE `files` (
`fid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL DEFAULT '0',
`filename` varchar(255) NOT NULL DEFAULT '',
`filepath` varchar(255) NOT NULL DEFAULT '',
`filemime` varchar(255) NOT NULL DEFAULT '',
`filesize` int(10) unsigned NOT NULL DEFAULT '0',
`status` int(11) NOT NULL DEFAULT '0',
`timestamp` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`fid`),
KEY `uid` (`uid`),
KEY `status` (`status`),
KEY `timestamp` (`timestamp`)
) ENGINE=MyISAM AUTO_INCREMENT=55 DEFAULT CHARSET=utf8$$
Apart from multiple syntax errors in your code you can't change column values of a row being inserted in AFTER trigger. You should use BEFORE event instead.
That being said your trigger can be boiled down to one-statement and therefore doesn't need BEGIN ... END block and change of a delimiter.
CREATE TRIGGER csv_fillpath
BEFORE INSERT ON content_type_importcsv
FOR EACH ROW
SET NEW.field_csvfilepath_value =
(
SELECT filepath
FROM files
WHERE fid = NEW.field_csv1_fid
LIMIT 1
);
Here is SQLFiddle demo
There are some syntax errors:
The one you listed is caused by the : in set p :=, you should remove it
Each line between begin and end$$ should end with ;
You can't update a NEW row in an after trigger, so it should be a before trigger