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.
Related
I am programming a trigger (in workbench 8) for mysql that is triggered after an insert to the table, my trigger is as follows:
DELIMITER //
Drop trigger if exists tr_pago;
CREATE TRIGGER tr_pago after insert on pago for each row
BEGIN
declare ultimoidpago int;
declare idcompromisopago int;
declare idunidadrecaudadora int;
declare idboleta int;
Set ultimoidpago = new.IdPago
Set idcompromisopago = (select new.CP_IdCompromisoPago from pago where IdPago = ultimoidpago);
Set idunidadrecaudadora = (select UR_IdUnidadRecaudadora from compromiso_pago where IdCompromisoPago = idcompromisopago);
Set idboleta = (select IdBoleta from boleta where UR_IdUnidadRecaudadora = idunidadrecaudadora );
update pago set new.B_IdBoleta = idboleta where IdPago = ultimoidpago;
END
DELIMITER //
But when making an insert to the payment table, I get the following error:
Error Code: 1442. Can't update table 'pago' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
This is a MySQL restriction in a trigger. Within a trigger, it is not allowed to issue a DML statement (INSERT/UPDATE/DELETE) against any table that is referenced in the statement that caused the trigger to be fired.
Looks like we are wanting to set a column in the inserted row to a value.
This would typically be better handled in a BEFORE INSERT trigger. A BEFORE INSERT trigger is allowed to perform SELECT on other tables.
SET NEW.B_IdBoleta = expr ;
FOLLOWUP
It's not clear what we are intending this trigger to do. But we know it can't issue an UPDATE on pago.
Here's an example of a BEFORE INSERT trigger that attempts to set the value of the b_idboleta column from the result of a query. We add a continue handler to catch the error if the SELECT query doesn't return a row.
DELIMITER //
CREATE TRIGGER tr_pago
BEFORE INSERT ON pago
FOR EACH ROW
BEGIN
DECLARE CONTINUE HANDLER FOR 1329 BEGIN SET NEW.b_idboleta = NULL; END;
SELECT bo.idboleta
INTO NEW.b_idboleta
FROM compromiso_pago cp
JOIN boleta bo
ON bo.ur_idunidadrecaudadora = cp.ur_idunidadrecaudadora
WHERE cp.idcompromisopago = NEW.cp_idcompromisopago
ORDER
BY bo.idboleta
LIMIT 1;
END//
DELIMITER ;
I have created one stored procedure which inserts a record into table and gets auto incremented ID of that record. Here I am getting an syntax error while setting LAST_INSERT_ID() into a variable.
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 ');
SET _orderId = SELECT LAST_INSERT_ID(); END' at line 5
Please help me to solve this issue. Thanks in Advance.
My code is like below:
DELIMITER //
CREATE PROCEDURE placeOrder(IN _cartId INT, IN _createdBy INT)
BEGIN
DECLARE _orderId INT;
-- insert into order
INSERT INTO `TBL_ORDER`(`DealerId`, `OrderNo`, `CreatedBy`)
VALUES ((SELECT DealerId FROM TBL_SHOPPING_CART WHERE Id = _cartId), UNIX_TIMESTAMP(), _createdBy));
SET _orderId = SELECT LAST_INSERT_ID();
END//
DELIMITER ;
Try this.
delimiter //
CREATE PROCEDURE placeOrder(IN _cartId INT,IN _createdBy INT)
BEGIN
SET #orderId = '';
-- insert into order
INSERT INTO `TBL_ORDER`(`DealerId`, `OrderNo`, `CreatedBy`) VALUES ((SELECT DealerId FROM TBL_SHOPPING_CART WHERE Id = _cartId),UNIX_TIMESTAMP(),_createdBy));
SELECT LAST_INSERT_ID() INTO #orderId;
END//
delimiter ;
OR
delimiter //
CREATE PROCEDURE placeOrder(IN _cartId INT,IN _createdBy INT)
BEGIN
-- insert into order
INSERT INTO `TBL_ORDER`(`DealerId`, `OrderNo`, `CreatedBy`) VALUES ((SELECT DealerId FROM TBL_SHOPPING_CART WHERE Id = _cartId),UNIX_TIMESTAMP(),_createdBy);
SELECT LAST_INSERT_ID() AS '_orderId ';
END//
delimiter ;
You should make sure that your application is not having a global connection or shared connection. As last_insert_it() will return the last generated AI value it can be from any table. Especially if your host application is using async TASKs
Consider following scenario
Your application saves gps location every second => generating new AI value
You're trying above SP to insert a value => Generating new AI value
Between your insert and read last_insert_id, your application logs gps location again and created new AI value.
Now guess what happens? you get the last inserted id from the gps table not from your SP.
usually insert's are fast, but assume your SP had to wait for a table lock and got delayed. In such case, you will receive wrong ID.
Safest way can be to escapsulate your SP work within a transaction and get the max value of your AI column (assuming it's an unsigned AI column).
Try:
...
-- SET _orderId = SELECT LAST_INSERT_ID();
SET _orderId = LAST_INSERT_ID();
SELECT _orderId;
...
or
...
-- SET _orderId = SELECT LAST_INSERT_ID();
SET _orderId = (SELECT LAST_INSERT_ID());
SELECT _orderId;
...
This is my trigger.
I want to make trigger on 1 table (rezervare).
Trigger
DELIMITER //
CREATE TRIGGER verificare_nr_locuri
BEFORE INSERT ON Rezervare
FOR EACH ROW
BEGIN
IF ( SELECT Masa.NrLocuri FROM Rezervare, Masa
WHERE Masa.NumarMasa = Rezervare.NumarMasa ) < Rezervare.NumarPersoane THEN
SET NEW.NumarMasa = NULL;
END IF;
END //
DELIMITER ;
INSERT INTO Rezervare VALUES (123,106,2,'2016-12-11','2016-12-24',5);
INSERT INTO Rezervare VALUES (124,106,2,'2016-12-11','2016-12-24',4);
When I execute the trigger, it has been created. But, when I insert data into table rezervare, It become
#1109 - Unknown table 'rezervare' in field list.
How can I resolve this?
Table
I think you might need to use a JOIN for your SELECT clause.
BEGIN
IF (SELECT Masa.NrLocuri, Rezervare.NumarMasa FROM Masa JOIN Rezervare
WHERE Masa.NumarMasa = Rezervare.NumarMasa) < Rezervare.NumarPersoane THEN
SET NEW.NumarMasa = NULL;
END IF;
I can enforce data restriction at the time of data insertion in a table using a trigger like following:
create table com(id int);
DELIMITER ;;
CREATE TRIGGER checkage_bi BEFORE INSERT ON com FOR EACH ROW
BEGIN
DECLARE dummy,baddata INT;
SET baddata = 0;
IF NEW.id > 20 THEN
SET baddata = 1;
END IF;
IF NEW.id < 1 THEN
SET baddata = 1;
END IF;
IF baddata = 1 THEN
SELECT CONCAT('Cannot Insert This Because id ',NEW.id,' is Invalid')
INTO dummy FROM information_schema.tables;
END IF;
END;;
this will restrict the values which will not meet the restriction condition.
But the problem is that if I insert multiple values along then for some values which do not meet the condition the other values will also be restricted from entry to table.
What I want is that when I insert multiple values along then the values that do not meet the condition should be skipped and the rest get inserted into the table
i.e. no any error is given.
Only the the bad values will be skipped and the other values will be inserted that's it.
Please give me some idea to do so.Thanks in advance...
You should better use stored Procedures rather than triggers for this purpose because you are not permitted within a stored function or trigger to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger itself.
DELIMITER ;;
create table com(id int,var char(40));;
create procedure Validate(IN id int,IN var char(40))
BEGIN
declare entry_id int;
SET entry_id=id;
IF (id > 20) OR (id < 1) THEN
SET entry_id=NULL;
END IF;
insert into com values(entry_id,var);
END;;
Here is the output screen
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.