I'll start by explaining how the db should work:
In this example I have a table that stores work orders, this table has 5 total fields: ID, Number, Worker, temperature, humidity.
And another table that stores sensor data with 4 fields: ID, Device ID, Temp, Hum.
We built an APP that allows workers to submit work order data, My problem comes here The app generates the ID, Number and Worker field, and we want to add the sensor data (Temperature and humidity) to that table every time an insert is made. I tried doing this with a trigger but i get "Error Code: 1442. Can't update table 'ordenes' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
I tried multiple ways of doing it but I either get no change on the table or that error message.
Im looking for a way to do this:
trigger after insert
> insert into "new created line"(temperature, humidity) values
(select temp,humidity from sensors order by id desc limit 1)
Thanks in advance
EDIT:
Create Scheme and table:
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
CREATE SCHEMA IF NOT EXISTS `Cegasa` DEFAULT CHARACTER SET utf8 ;
USE `Cegasa` ;
DROP TABLE IF EXISTS `Cegasa`.`ORDENES` ;
CREATE TABLE IF NOT EXISTS `Cegasa`.`ORDENES` (
`idORDENES` INT NOT NULL AUTO_INCREMENT,
`NumOrden` VARCHAR(45) NULL,
`Empleado` VARCHAR(45) NULL,
`Temperatura` VARCHAR(45) NULL,
`Humedad` VARCHAR(45) NULL,
PRIMARY KEY (`idORDENES`))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `Cegasa`.`sensores` ;
CREATE TABLE IF NOT EXISTS `Cegasa`.`sensores` (
`id` INT NOT NULL AUTO_INCREMENT,
`EUI` VARCHAR(45) NULL,
`Temp` VARCHAR(45) NULL,
`Hum` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
USE `Cegasa`;
DELIMITER $$
USE `Cegasa`$$
DROP TRIGGER IF EXISTS `Cegasa`.`ORDENES_AFTER_INSERT` $$
USE `Cegasa`$$
CREATE DEFINER = CURRENT_USER TRIGGER `Cegasa`.`ORDENES_AFTER_INSERT` AFTER INSERT ON `ORDENES` FOR EACH ROW
BEGIN
insert into `cegasa`.`Ordenes` (
`temp`,
`hum`
) SELECT temp,hum FROM sensores ORDER BY ID DESC LIMIT 1;
END$$
DELIMITER ;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
Insert for example sensor data:
INSERT INTO `cegasa`.`sensores`
(`id`,
`EUI`,
`Temp`,
`Hum`)
VALUES
(default,
"th312322aa",
"10",
"33"),(
default,
"daedaf12392",
"30",
"70"
);
Similar insert to the one the app makes
INSERT INTO `cegasa`.`ordenes`
(`idORDENES`,
`NumOrden`,
`Empleado`)
VALUES
(default,
1,
"123a");
Desired outcome after this insert
CREATE TABLE IF NOT EXISTS `sensores` (
`id` INT NOT NULL AUTO_INCREMENT,
`EUI` VARCHAR(45) NULL,
`Temp` VARCHAR(45) NULL,
`Hum` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `sensores` (`id`,`EUI`,`Temp`,`Hum`) VALUES
(default, "th312322aa", "10", "33"),
(default, "daedaf12392", "30", "70");
SELECT * FROM sensores;
id
EUI
Temp
Hum
1
th312322aa
10
33
2
daedaf12392
30
70
CREATE TABLE IF NOT EXISTS `ordenes` (
`idORDENES` INT NOT NULL AUTO_INCREMENT,
`NumOrden` VARCHAR(45) NULL,
`Empleado` VARCHAR(45) NULL,
`Temperatura` VARCHAR(45) NULL,
`Humedad` VARCHAR(45) NULL,
PRIMARY KEY (`idORDENES`))
ENGINE = InnoDB;
CREATE TRIGGER get_last_Temp_Hum
BEFORE INSERT ON ordenes
FOR EACH ROW
BEGIN
DECLARE new_temp VARCHAR(45); -- declare intermediate variables
DECLARE new_hum VARCHAR(45);
SELECT Temp, Hum INTO new_temp, new_hum -- select vast values into it
FROM sensores
ORDER BY id DESC LIMIT 1;
SET NEW.Temperatura = new_temp, -- set columns values in newly inserted row
NEW.Humedad = new_hum; -- to the values stored in the variables
END
INSERT INTO `ordenes` (`idORDENES`,`NumOrden`,`Empleado`) VALUES
(default, 1, "123a");
SELECT * FROM ordenes;
idORDENES
NumOrden
Empleado
Temperatura
Humedad
1
1
123a
30
70
fiddle
Trigger fires on INSERT statement but before the values are inserted into the table (i.e. the insertion is an intention yet). The query in the trigger retrieves needed values into the variables, then SET statement copies these values into the columns in the row which will be inserted. And after the trigger finishes the row contains needed values in the columns, and these values are saved into the table.
I want to use a function inside a select query.
This is my test database.
When I use a select, get a result, but the function is running twice... why? I want to insert one row in this case.
Help, please!
create database db1_test;
use db1_test;
create table t1(
id int(11) primary key auto_increment,
t1col1 varchar(20) not null,
t1col2 int(1) not null
);
create table t2(
id int(11) primary key auto_increment,
t2col1 int(11) not null,
t2col2 datetime
);
insert into t1 (t1col1, t1col2) values ('row1', 1);
insert into t1 (t1col1, t1col2) values ('row2', 0);
insert into t1 (t1col1, t1col2) values ('row4', 1);
drop function if exists func1;
DELIMITER $$
CREATE FUNCTION func1(id int) RETURNS datetime
BEGIN
insert into t2 (`t2col1`, `t2col2`) values (id, now());
RETURN now();
END $$
DELIMITER ;
TEST :
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row1';
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row2';
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row4';
Functions are generally used to store reuseable code which returns a scalar value from a calculation or transformation. I think you could
insert into t2(t2col1,t2col2)
SELECT id, now()
FROM `t1`
WHERE `t1`.`t1col1`='row1';
My triger It works normally but if i use procedur in the insert I'm getting the error
1442 - Can't update table 'stock' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
bu if i use manuel insert into table panier Normal inserted does not show me the error :'(
i use it like that :
call temps;
call stock_panier(94,19,'tranche');
call panier_ins(22547153,6185,null,now());
my triger :
DELIMITER $$
CREATE TRIGGER Stock_cal BEFORE INSERT on panier
FOR EACH ROW BEGIN
DECLARE is_exist INT;
DECLARE is_exist1 INT;
DECLARE is_exist2 INT;
set is_exist = (select stock.qte_res_s from stock WHERE stock.code_s=new.code_s);
set is_exist1 = new.qte_p;
set is_exist2 = new.qte_p;
if (is_exist<is_exist1) OR (is_exist2<1) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '✘: Opération a été refusée.';
ELSE
UPDATE stock SET qte_res_s=qte_res_s-new.qte_p,qte_sor_s=qte_sor_s+new.qte_p WHERE new.code_s=stock.code_s ;
END if;
END$$
DELIMITER ;
my table temperer :
CREATE PROCEDURE `temps`()
BEGIN
call virifier_table_exist('panier_tm');
if (#table_exists)=0 THEN
CREATE TEMPORARY TABLE `panier_tm` (
`N_p` bigint(20) DEFAULT Null,
`N` bigint(20) DEFAULT null,
`Code_barr` varchar(100) DEFAULT NULL,
`Référence` varchar(40) DEFAULT NULL,
`Désignation` varchar(40) DEFAULT NULL,
`Prix_HT` varchar(20) DEFAULT NULL,
`Fournisseur` varchar(30) DEFAULT NULL,
`Magasin` varchar(10) DEFAULT NULL,
`Qte_Vent` varchar(5) DEFAULT NULL,
`code_s` bigint(20) DEFAULT NULL,
`code_d` bigint(20) DEFAULT NULL,
tva_p varchar(5) DEFAULT Null,
type_ver varchar(15) DEFAULT null);
SET #row_number:=0;
else
DROP TEMPORARY TABLE `panier_tm`;
CREATE TEMPORARY TABLE `panier_tm` (
`N_p` bigint(20) DEFAULT Null,
`N` bigint(20) DEFAULT null,
`Code_barr` varchar(100) DEFAULT NULL,
`Référence` varchar(40) DEFAULT NULL,
`Désignation` varchar(40) DEFAULT NULL,
`Prix_HT` varchar(20) DEFAULT NULL,
`Fournisseur` varchar(30) DEFAULT NULL,
`Magasin` varchar(10) DEFAULT NULL,
`Qte_Vent` varchar(5) DEFAULT NULL,
`code_s` bigint(20) DEFAULT NULL,
`code_d` bigint(20) DEFAULT NULL,
tva_p varchar(5) DEFAULT Null,
type_ver varchar(15) DEFAULT null);
SET #row_number:=0;
end if;
END$$
DELIMITER ;
my procedure :
drop PROCEDURE if EXISTS panier_ins ;
DELIMITER $$
CREATE PROCEDURE panier_ins (in code_cccp varchar(30), code_cl1 bigint(20),N_p1 bigint(20),dat date)
BEGIN
DECLARE code_faa varchar(20);
DECLARE n_p2 bigint(20);
START TRANSACTION;
if (SELECT COUNT(Qte_Vent) from panier_tm tm2,stock WHERE tm2.code_s=stock.code_s and tm2.Qte_Vent>stock.qte_res_s and not EXISTS (select 1 from panier_vu vu2 where tm2.N_p=vu2.code_p and tm2.code_s=vu2.code_s ))>0 THEN
SELECT "Veuillez vous assurer que le stock est terminé" AS message ;
ELSE
set #count_n_p=(select COUNT(n_p) from panier_tm where n_p=n_p1);
set #n_p=(select n_p from panier_tm where n_p=n_p1);
if (#n_p) is null OR (#count_n_p)=0 THEN
SET #n_p2=(SELECT MIN(t1.code_p+1) as id FROM panier t1 LEFT JOIN panier t2 On t1.code_p+1=t2.code_p Where t2.code_cl IS NULL);
set #n_p2=if(#n_p2 = null,1,#n_p2);
INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT #n_p2,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr and tm1.code_s=stock.code_s and NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
update panier_tm set N_p=#n_p2;
set code_faa=(SELECT MIN(SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1) as id FROM facture t1 LEFT JOIN facture t2 On SUBSTRING(t1.code_fa, 6, length(t1.code_fa)-5)+1=SUBSTRING(t2.code_fa, 6, length(t2.code_fa)-5) Where t2.code_fa IS NULL);
set code_faa= CONCAT( DATE_FORMAT(now(),"%Y"),"/",code_faa) ;
INSERT INTO `facture`(`autot`, `code_fa`, `code_ccp`, `code_cl`, `code_p`, `date_fa`, `type_ver`) VALUES (null,code_faa,code_cccp,code_cl1,#n_p2,now(),typ);
COMMIT ;
ELSE
START TRANSACTION;
INSERT INTO `panier`(`code_p`, `n_p`, `code_s`, `code_cl`, `type_ver_p`, `date_p`, `qte_p`, `prix_p`, `tva_p`) SELECT tm1.n_p,tm1.n,stock.code_s,code_cl1,type_ver,dat,qte_vent,prix_ht,tva_p FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr and tm1.code_s=stock.code_s and NOT EXISTS (select 1 from panier_vu vu1 where tm1.N_p=vu1.code_p and tm1.code_s=vu1.code_s);
DELETE b FROM `panier` b LEFT JOIN panier_tm f ON f.code_s = b.code_s and b.code_p=f.N_p WHERE code_p=n_p1 and f.N_p is null;
UPDATE `panier` p1,panier_tm tms SET p1.`n_p`=tms.N_p,p1.`qte_p`=tms.Qte_Vent,p1.`prix_p`=tms.Prix_HT,`tva_p`=tva1 WHERE p1.code_p=N_p1 and p1.code_s=tms.code_s;
COMMIT ;
END if;
END IF;
END$$
DELIMITER ;
Your problem are the two inserts into panier that depend on stock, while you have an on insert-trigger on panier that modifies the table stock that the insert into panier depends on:
INSERT INTO `panier`(`code_p`, ...) SELECT #n_p2,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...
INSERT INTO `panier`(`code_p`, ...) SELECT tm1.n_p,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...
They both have the structure
INSERT INTO panier (...) SELECT ... FROM stock ...
which is not allowed if you have an insert trigger on panier which modifies stock. These inserts are the statement which invoked this stored function/trigger in which you can't update table 'stock'. MySQL is for technical reasons not able to do this.
The straight forward technical workaround for this is to create a temporary table in which you store the result of your SELECT ..., and then insert into panier from that temporary table, e.g. something like
create temporary table tmp (...);
insert into tmp (...) select ... from stock ...;
insert into panier (...) select ... from tmp;
drop table tmp;
The insert-trigger now doesn't modify any dependent tables anymore, since you only select from tmp.
In your procedure, this would look like
create temporary table tmp (code_p bigint(20), n_p bigint(20),
..., tva_p varchar(5));
if (#n_p) is null OR (#count_n_p)=0 THEN
...
insert into tmp (code_p, n_p, ...)
SELECT #n_p2,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE reduit.code_pr=stock.code_pr ...
insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
...
else
...
insert into tmp (code_p, n_p, ...)
SELECT tm1.n_p,tm1.n,stock.code_s, ...
FROM `preduit`,`stock`,`panier_tm` tm1 WHERE preduit.code_pr=stock.code_pr ...
insert into panier (code_p, n_p, ...) select code_p, n_p, ... from tmp;
...
end if;
drop table tmp;
You can of course create the temporary table in your procedure temps.
It is also usually possible to redesign your procedure, triggers or logic so you do not need this, but that would probably be a larger endeavour.
And you should verify if that is actually the logic you want to apply, e.g. if you want to decide on the current state of stock which rows to insert, freeze this state (by putting it into the tmp-table) and then run the insert independently of how the stock-table changed during those inserts (e.g. if you would have inserted the 2nd row if you would have known what the first row changed in stock). I didn't check what your code is supposed to do, so this may or may not apply here, and may or may not be a problem here, but circular dependendies (and the error you get here because of it) can sometimes be a sign for an underlying problem.
I have created a table
CREATE TABLE testtab (
`id` int(11) NOT NULL AUTO_INCREMENT,
`customer_id` bigint(20) DEFAULT NULL,
`food_id` int(11) DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
)
Table contains below row
INSERT INTO testtab (`customer_id`, `food_id`, `created_date`)
VALUES ('433', '9', '2019-05-14 12:00:54');
Now the condition is for a specific customer_id there can be only one row with food_id either 8 or 9.
Now I try to add the below insert statement
INSERT INTO testtab (`customer_id`, `food_id`, `created_date`)
VALUES ('433', '8', '2019-05-14 12:00:54');
Now It should either get failed or get deleted immediately after inserted(record with tag_id=8).I have used the below trigger.But unfortunately i got error
Can't update table 'testtab' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
DELIMITER $$
USE `ipay`$$
DROP TRIGGER /*!50032 IF EXISTS */ `testtabTrigger`$$
CREATE
TRIGGER `testtabTrigger` AFTER INSERT ON `testtab`
FOR EACH ROW BEGIN
IF ((SELECT COUNT(*) FROM testtab WHERE food_id =9 AND customer_id = new.customer_id) =1 && new.food_id = 8) THEN
DELETE FROM testtab WHERE food_id = 8 AND customer_id = new.customer_id;
END IF;
END;
$$
DELIMITER ;
The idea is that you do something like this:
CREATE TRIGGER `testtabTrigger` BEORE INSERT ON `testtab`
FOR EACH ROW
BEGIN
IF (EXISTS (SELECT COUNT(*)
FROM testtab tt
WHERE tt.food_id = 9 AND
tt.customer_id = new.customer_id
) AND
new.food_id = 8
) THEN
signal sqlstate '45000' set message_text = 'Attempted insert of 8 when there is a 9';
END IF;
END;
as I'm working on a small app for managing metadata and I was wondering if it is possible to insert row in another table if conditions are met.
Let me follow with example: So, let's say we have table ispu_plan
CREATE TABLE `ispu_plan` (
`id` int(11) NOT NULL,
`id_jls` int(11) NOT NULL,
`id_razina_plan` int(11) NOT NULL,
`id_revizija` int(11) NOT NULL,
`naziv_plan` varchar(150) NOT NULL,
`ispu_naziv` varchar(100) NOT NULL,
`id_mjerilo` int(11) NOT NULL,
`datum_donosenja_plana` date DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and as I'm updating table ispu_plan I want to update another table (e.g. ispu_plan_updated) if certain conditions are met in ispu_plan with same rows from table ispu_plan
Using this query:
SELECT * FROM ispu_plan WHERE datum_donosenja_plana BETWEEN '2014-01-01' AND CURDATE()
I want to insert row in table ispu_plan_updated. Is something like this possible and can I insert rows in ispu_plan_updated using views?
Thank you
You can use a trigger to achieve that:
DROP TRIGGER IF EXISTS ispu_plan_trigger;
DELIMITER |
CREATE TRIGGER ispu_plan_trigger AFTER UPDATE ON ispu_plan
FOR EACH ROW BEGIN
-- example condition with update:
IF NEW.datum_donosenja_plana >= '2017-01-01' THEN
UPDATE ispu_plan_updated SET naziv_plan = 'some_value' WHERE id = NEW.id
LIMIT 1;
END IF;
END;
DELIMITER ;