Currently, I have bunch of triggers that do the same thing. This is copy-pasted for every table that needs this functionality.
delimiter $$
create trigger user_before_insert before insert on user for each row
begin
set NEW.create_time = CURRENT_TIMESTAMP;
set NEW.create_user_id = #user_id;
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
create trigger user_before_update before update on user for each row
begin
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
Is it possible to wrap the lines that modify OLD and/or NEW into stored procedures that are called via triggers? Something like this:
delimiter $$
create procedure autofill_on_insert(inout NEW data_type) -- what would be the data_type?
begin
set NEW.create_time = CURRENT_TIMESTAMP;
set NEW.create_user_id = #user_id;
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
create procedure autofill_on_update(inout NEW data_type) -- what would be the data_type?
begin
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
delimiter ;
create trigger user_before_insert before insert on user
for each row call autofill_on_insert(NEW);
create trigger user_before_update before update on user
for each row call autofill_on_update(NEW);
Additional question: if this is possible, is there any way to check if NEW contains specific columns? There are tables that do not have modify_time and modify_user_id.
I can say that NEW cannot be passed into the procedure, because NEW is an alias that represents a row. Procedure's arguments have to be scalar values, like INT, VARCHAR, etc..
About the 'SET NEW.create_time = CURRENT_TIMESTAMP;'; if field create_time is a TIMESTAMP, you could set CURRENT_TIMESTAMP as default value for it.
Related
I have a trigger that should work, but it does not work.
BEGIN
DECLARE `refresh` VARCHAR(256);
SET `refresh` = concat((SELECT `refresh` FROM `mobile_app_drivers` WHERE `id` = 1), '&');
UPDATE `mobile_app_drivers` SET `refresh` = #refresh WHERE `id` = 1;
END
When it is executed, the cell **refresh** still broadcasts an empty string.
// HOW I CREATE IT
DROP TRIGGER IF EXISTS `SET_UNIQUE_KEY`;
CREATE DEFINER=`root`#`localhost` TRIGGER `SET_UNIQUE_KEY` AFTER UPDATE ON `mobile_app_orders` FOR EACH ROW
BEGIN
DECLARE `refresh` VARCHAR(256);
SET `refresh` = concat((SELECT MAX(`refresh`) FROM `mobile_app_drivers` WHERE `id` = 1), '&');
UPDATE `mobile_app_drivers` SET `refresh` = #refresh WHERE `id` = NEW.driver;
END
I need, when any record from the table is updated, then a new substring was added from the value refresh from the table mobile_app_drivers.
Thank you!
You are using session variable #refresh. However, you have not defined it anywhere. So it will considered empty only.
I modified your trigger to make it more clear and logical to follow. Declared a new variable new_refresh and we can set its value using Into clause inside a Select statement.
Now, call the update statement.
Also, you need to redefine Delimiter to something else (eg: $$), instead of (;).
At the end, redefine the DELIMITER to ;
You can modify your Create Trigger statement to as follows:
DELIMITER $$
DROP TRIGGER IF EXISTS `SET_UNIQUE_KEY` $$
CREATE DEFINER=`root`#`localhost` TRIGGER `SET_UNIQUE_KEY` AFTER UPDATE ON `mobile_app_orders` FOR EACH ROW
BEGIN
DECLARE new_refresh VARCHAR(256) DEFAULT '';
SELECT CONCAT(MAX(`refresh`), '&') INTO `new_refresh`
FROM `mobile_app_drivers`
WHERE `id` = 1;
UPDATE `mobile_app_drivers` SET `refresh` = new_refresh WHERE `id` = NEW.driver;
END $$
DELIMITER ;
Why are you using a variable? Just do:
DROP TRIGGER IF EXISTS `SET_UNIQUE_KEY`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` TRIGGER `SET_UNIQUE_KEY` AFTER UPDATE ON `mobile_app_orders`
FOR EACH ROW
BEGIN
UPDATE mobile_app_drivers CROSS JOIN
(SELECT MAX(refresh) as max_refresh
FROM mobile_app_drivers
WHERE id = 1
) mad1
SET refresh = concat(mad1.max_refresh, '&')
WHERE id = NEW.driver;
END;
DELIMITER ;
I'm running an insert into a members table and when a new row is added I want to run a trigger to update the username field of the members table but it wont let me due to constraints due to possible deadlock situations.
DELIMITER //
CREATE TRIGGER tr_add_member
AFTER INSERT ON td_members
FOR EACH ROW BEGIN
IF mem_username = '' THEN
SET mem_username = CONCAT('user' , mem_id);
END IF;
END//
DELIMITER ;
I've tried using the OLD and NEW keywords but they don't work, I've removed the NEW and OLD keywords above but get the below error with this trigger.
ERROR 1193 (HY000): Unknown system variable 'mem_username'
Should I be calling a procedure from the trigger to do what I want it and just run a simple UPDATE statement from within the procedure?
You have to use BEFORE INSERT trigger, but not an AFTER INSERT.
And if mem_id is auto incremented primary key field, then find its
next auto increment value from information_schema.tables and use it.
Change your trigger code as follows:
DELIMITER //
DROP TRIGGER IF EXISTS tr_add_member //
CREATE TRIGGER tr_add_member
BEFORE INSERT ON td_members
FOR EACH ROW
BEGIN
DECLARE _mem_id INT DEFAULT 0;
IF length( trim( NEW.mem_username ) ) = 0 THEN
SELECT AUTO_INCREMENT INTO _mem_id
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'td_members'
AND TABLE_SCHEMA = DATABASE();
SET NEW.mem_username = CONCAT( 'user', _mem_id );
END IF;
END;
//
DELIMITER ;
This is the database vehicle table's trigger
DROP TRIGGER IF EXISTS InsertVehTrig;
DELIMITER $$
CREATE TRIGGER InsertVehTrig AFTER INSERT
ON Vehicle FOR EACH ROW
SWL_return:
BEGIN
DECLARE Cph CHAR(50);
DECLARE DevID CHAR(12);
DECLARE VehID BIGINT;
DECLARE TmpID BIGINT;
DECLARE DevCount INT;
SET Cph = rtrim(ltrim(NEW.cph));
SET VehID = NEW.ID;
SET DevID = NEW.DevID;
if(VehID is null) then
select count(id) into #DevCount from vehicle where (cph=#Cph) or (DevID=#DevID);
-- 条件:当前的车牌号 或 设备ID
end if;
if (DevCount > 1) then -- 如果记录数,超过1,则认为有重复
-- Rollback not supported in trigger
SET #SWV_Null_Var = 0;
Leave SWL_return;
else
if (DevCount = 1) then
select ID INTO #TmpID from Vehicle where (Vehicle.cph = #Cph) or (Vehicle.DevID = #DevID);
if (TmpID != VehID) then -- --如果增加的车牌号码与数据库中的在相同的,则不允许增加
-- Rollback not supported in trigger
Leave SWL_return;
SET #SWV_Null_Var = 0;
end if;
end if;
end if;
update vehicle set cph = #Cph where ID = #VehID;
END;
Right now i m trying to insert new data row in the vehicle table, but error with this
ERROR 1442: Can't update table 'vehicle' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
SQL Statement:
INSERT INTO `gis_server`.`vehicle` (`TrackerNum`, `cph`, `DevID`, `DevType`) VALUES ('1', 'NR09B00555', 'NR09B00555', '2')
those database are designed by 3 party company,
How do i insert data to vehicle table?
You can achieve this by making two changes to your approach:
Firstly, use a BEFORE trigger rather than an AFTER
Secondly, rather than updating the same table, update the NEW table, setting the column value to the new value before the NEW table hits the table targeted by the INSERT.
For example, replace your UPDATE line with the following:
UPDATE NEW SET cph = Cph;
MySQL doesn't allow you to edit the data in the table on which a trigger is created in that trigger, but you can edit the NEW table to modify the values going into that table.
The default initial value of one column in my database is the same as the row's auto-incremented id. I'm trying to use triggers to set it.
CREATE TRIGGER `default_order_value`
AFTER INSERT ON `clusters`
FOR EACH ROW
BEGIN
UPDATE `clusters` SET `order` = NEW.id WHERE `id` = NEW.id;
END
But this keeps throwing a syntax error
#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 '' at line 5
I've tried all sorts of permutations of this with no luck. Can anyone see what I'm doing wrong?
As zerkms said, you need to change the delimeter. But since you only use 1 line of code, you don't need the BEGIN and END. And that way, you don't need to change the delimiter either
CREATE TRIGGER `default_order_value`
AFTER INSERT ON `clusters`
FOR EACH ROW
UPDATE `clusters` SET `order` = NEW.id WHERE `id` = NEW.id;
Since you are getting an error you cannot update the row, I suggest the following:
Do NOT perform the update query at all. On default the order value = the ID value. So when the order value changes, you can update it properly.
If you are requesting the data with php, do something like this:
$order = $row['order'];
if ($order == '')
$order = $row['id'];
After you need it updating, you've got the correct value.
I don't think you can do that. An AFTER INSERT trigger cannot modify the same table, neither by issuing an UPDATE nor by something like this:
CREATE TRIGGER `default_order_value`
AFTER INSERT ON `clusters`
FOR EACH ROW
SET NEW.`order` = NEW.id ;
which results in this error:
> Error Code: 1362. Updating of NEW row is not allowed in after trigger
You can't either use a BEFORE INSERT trigger because then the NEW.id is not known (if you modify the above, the order column will get 0 value after the Insert.
What you can do, is use a transaction:
START TRANSACTION ;
INSERT INTO clusters (id)
VALUES (NULL);
UPDATE clusters
SET `order` = id
WHERE id = LAST_INSERT_ID();
COMMIT ;
You get the error because mysql treats ; in line 5 as the end of your trigger declaration, which obviously leads to the syntax error.
So you need to redefine delimiter before you specify the trigger body:
delimiter |
CREATE TRIGGER `default_order_value`
AFTER INSERT ON `clusters`
FOR EACH ROW
BEGIN
UPDATE `clusters` SET `order` = NEW.id WHERE `id` = NEW.id;
END;
|
delimiter ;
You can create just BEFORE INSERT TRIGGER, it's works like this:
CREATE TRIGGER `default_order_value`
BeFORE INSERT ON `clusters`
FOR EACH ROW
BEGIN
SET NEW.`order` = NEW.id ;
END
same as below we are using
DELIMITER $$
USE `e_store`$$
DROP TRIGGER /*!50032 IF EXISTS */ `Test`$$
CREATE
/*!50017 DEFINER = 'root'#'%' */
TRIGGER `Test` BEFORE INSERT ON `categories`
FOR EACH ROW
BEGIN
DECLARE vtype VARCHAR(250) DEFAULT NULL;
SET vtype = NEW.name;
IF (NEW.MDNAME IS NULL)
THEN
-- SET NEW.MDNAME = 'NA';
SET NEW.MDNAME=MD5(NEW.name);
END IF;
END;
$$
DELIMITER ;
This worked for me:
CREATE TRIGGER `update_table_2`
AFTER UPDATE ON `table_1`
FOR EACH ROW
UPDATE table2
JOIN table_1
SET table_2.the_column = NEW.the_column
WHERE table_2.auto_increment_field = OLD.auto_increment_field
Is it possible to declare that a column in MySQL should be unmodifiable once initially set? I have a column that has the following definition: created timestamp default current_timestamp and I'd like to make sure that nobody messes with it after my rows are created.
You can accomplish this using a BEFORE UPDATE trigger:
DELIMITER $$
CREATE TRIGGER trFoo BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
IF NEW.Bar != OLD.Bar THEN
SET NEW.Bar = OLD.Bar;
END IF;
END$$
DELIMITER ;