CREATE TABLE `inventory` (
`id` int(11) NOT NULL,
`owner` int(11) DEFAULT NULL,
`grade1` int(11) DEFAULT NULL,
`grade2` int(11) NOT NULL,
`grade3` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `inventory`
--
INSERT INTO `inventory` (`id`, `owner`, `grade1`, `grade2`, `grade3`) VALUES
(3, 1, 2, 1, 1);
-- --------------------------------------------------------
--
-- Table structure for table `transfer`
--
CREATE TABLE `transfer` (
`id` int(11) NOT NULL,
`owner` int(11) DEFAULT NULL,
`total` char(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `transfer`
--
INSERT INTO `transfer` (`id`, `owner`, `total`) VALUES
(20, 1, 1);
--
-- Triggers `transfer`
--
DELIMITER $$
CREATE TRIGGER `t` AFTER INSERT ON `transfer` FOR EACH ROW update inventory t1
set t1.grade1 = t1.grade1 + 1
WHERE t1.owner = new.owner
AND `total` = '/1'
$$
DELIMITER ;
I have two tables as you can see from above code. I am in the process of using triggers in MySQL.
What I am trying to do, is that when someone enters something into transfer, and the owner matches the owner which is in the inventory- if what they have typed '(a number)/1' into total in transfer, it would add 1 to grade1. If they typed in '(a number)/2' into total, it will add 1 to grade2. And same for grade3. As you can see from the trigger above, this is what I have tried. I have tried it without the AND `total` = '/1' so I know the issue must be within that part. I have also tried without the ` around total, however it doesn't recognise this column without it.
I've had a look through SO and cannot find anything to resolve this.
I need this section done through a trigger- if anyone has any idea, can they please let me know. Thanks
The usual way to update different columns conditionally is to update all of them, but use a condition to determine whether to give them a new value or keep the old value. This can be used in a trigger just like any other UPDATE query.
CREATE TRIGGER `t` AFTER INSERT ON `transfer` FOR EACH ROW update inventory t1
set t1.grade1 = IF(new.total LIKE '%/1', t1.grade1 + 1, t1.grade1),
t1.grade2 = IF(new.total LIKE '%/2', t1.grade2 + 1, t1.grade2),
t1.grade3 = IF(new.total LIKE '%/3', t1.grade3 + 1, t1.grade3)
WHERE t1.owner = new.owner
It seems like what you really need is a fourth column grade in the transfer table so your trigger code can know which grade to increment. All you have in the trigger is OLD.* and NEW.*, the columns of the row that changed. You can't make one of your current integer columns carry extra information that is more than a simple integer.
ALTER TABLE transfer ADD COLUMN grade TINYINT UNSIGNED;
Then you can use this in the trigger to tell which grade to increment.
CREATE TRIGGER `t` AFTER INSERT ON `transfer` FOR EACH ROW
UPDATE inventory
SET grade1 = grade1 + CASE NEW.grade WHEN 1 THEN 1 ELSE 0 END,
grade2 = grade2 + CASE NEW.grade WHEN 2 THEN 1 ELSE 0 END,
grade3 = grade3 + CASE NEW.grade WHEN 3 THEN 1 ELSE 0 END;
WHERE owner = NEW.owner
Related
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.
DROP TABLE IF EXISTS Sales;
CREATE TABLE Sales (
id INT AUTO_INCREMENT,
product VARCHAR(100) NOT NULL,
quantity INT NOT NULL DEFAULT 0,
fiscalYear SMALLINT NOT NULL,
fiscalMonth TINYINT NOT NULL,
CHECK(fiscalMonth >= 1 AND fiscalMonth <= 12),
CHECK(fiscalYear BETWEEN 2000 and 2050),
CHECK (quantity >=0),
UNIQUE(product, fiscalYear, fiscalMonth),
PRIMARY KEY(id)
);
DROP TABLE IF EXISTS log;
CREATE TABLE log (
id INT AUTO_INCREMENT PRIMARY KEY,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
text VARCHAR(100)
);
Triggers
CREATE DEFINER=`root`#`localhost` TRIGGER `sales_AFTER_UPDATE` AFTER UPDATE ON `sales`
FOR EACH ROW
BEGIN
INSERT INTO log VALUES(NOW(),CONCAT('Update Student Record ', OLD.quantity));
END
UPDATE test for.sales SET quantity = 36
WHERE (id = 1);
ERROR 1136: 1136: Column count doesn't match value count at row 1
Iam new in mySQL Please help
You should specify columns in INSERT statement in your trigger explicitly, as you do not set all values in a row (auto incremented column excluded).
So it would be
INSERT INTO log(timestamp, text) VALUES (NOW(),CONCAT('Update Student Record ', OLD.quantity));
You have some errors.
First based on your trigger you need another column on log table which is as following
quantity INT NOT NULL DEFAULT 0
Second , do not use Keywords and Reserved Words like text and timestamp, it is a bad practice. If you do please put it inside backticks
Third your insert statement should be
INSERT INTO log(`timestamp`,`text`,quantity) VALUES(NOW(),'Update Student Record', OLD.quantity);
there is no need for CONCAT.
Fourth,
`sales`
table is not the same as Sales table, because you have used backticks.
Full working trigger below:
DELIMITER //
CREATE TRIGGER `sales_AFTER_UPDATE` AFTER UPDATE ON Sales
FOR EACH ROW
BEGIN
INSERT INTO log(`timestamp`,`text`,quantity) VALUES(NOW(),'Update Student Record', OLD.quantity);
END//
DELIMITER ;
Check working demo:
https://www.db-fiddle.com/f/iqwShcHK3AGJvU4MDbxDku/0
I have two tables:
CREATE TABLE `class` (
`id` int(11) NOT NULL,
`class_no` int(11) NOT NULL,
`class_title` varchar(11) NOT NULL,
`no_of_students` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `enrolment` (
`id` int(11) NOT NULL,
`ssn` varchar(11) NOT NULL,
`class_no` int(11) NOT NULL,
`grade` varchar(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
What I am trying to do is when someone enters into 'Enrolment', if the class number entered matches an entry in 'Class', e.g. class number 2 - then i want what is typed into grade on 'Enrolment' (i.e 5) to add to whatever is already in number of students (Say if it's 10). In this case, the number of students would then say 15. This is the current trigger i have, however is not adding:
DELIMITER $$
CREATE TRIGGER `after_insert_add_one` AFTER INSERT ON `enrolment` FOR EACH ROW UPDATE class
SET class.no_of_students = class.no_of_students + enrolment.grade WHERE class_no = NEW.class_no
$$
DELIMITER ;
If anyone knows i'd be grateful for the help.
You must use the NEW key instead of the name of table enrolment, try this
CREATE TRIGGER `after_insert_enrolment` AFTER INSERT ON `enrolment`
FOR EACH ROW BEGIN
UPDATE class c
SET
c.no_of_students = c.no_of_students + NEW.grade
WHERE c.class_no = NEW.class_no;
END
You’re not making changes with SET class.no_of_students = class.no_of_students + enrolment.grade if you’re not using enrolment.class_no to compare using where clause. Update it with NEW in place of enrolment if you’re using it:
DELIMITER $
CREATE TRIGGER `after_insert_add_one` AFTER INSERT ON `enrolment` FOR EACH ROW UPDATE class
SET class.no_of_students = class.no_of_students + NEW.grade WHERE class_no = NEW.class_no
$
DELIMITER ;
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 ;
This is my schema:
I am trying to have an insert into "desktops" or "laptops" insert an id generated automatically from "computers". That works.
My issue is when I insert into either table, I can not select last_insert_id();
Is there something I am doing wrong? I am trying to pass the id all the way forward to my application, for further processing. Selecting MAX(id) is not a valid solution. My SQL connection makes one insert statement, and the trigger should not break that functionality...
Use test;
CREATE TABLE `laptops` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=innodb DEFAULT CHARSET=utf8;
CREATE TABLE `desktops` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=innodb DEFAULT CHARSET=utf8;
CREATE TABLE `computers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=innodb DEFAULT CHARSET=utf8;
CREATE TRIGGER `laptops_BINS` BEFORE INSERT ON `laptops` FOR EACH ROW
BEGIN
IF (EXISTS(SELECT id FROM laptops WHERE name = NEW.name)) THEN
SET NEW.id = NULL;
ELSE
INSERT INTO computers (type) VALUES ('laptop');
SET NEW.id = LAST_INSERT_ID();
SET NEW.id = LAST_INSERT_ID(NEW.id);
END IF;
END
CREATE TRIGGER `desktop_BINS` BEFORE INSERT ON `desktops` FOR EACH ROW
BEGIN
IF (EXISTS(SELECT id FROM desktops WHERE name = NEW.name)) THEN
SET NEW.id = NULL;
ELSE
INSERT INTO computers (type) VALUES ('desktop');
SET NEW.id = LAST_INSERT_ID();
SET NEW.id = LAST_INSERT_ID(NEW.id);
END IF;
END
INSERT INTO laptops (name) VALUES ('laptop1');
INSERT INTO laptops (desktop) VALUES ('desktop1');
INSERT INTO laptops (name) VALUES ('laptop2');
INSERT INTO laptops (desktop) VALUES ('desktop2');
SELECT last_insert_id();
Expecting 4, actually its 0.
Any thoughts as to how I can fix the trigger? Maybe someone can help me format the AFTER_INSERT statement to fix last_insert_id?
I tried setting the values to auto-increment, and unique in the laptops and desktops table, neither will fix the issue.
Rather than trying to deal with the 'confusion' of 'last_insert_id'. I decided to change the table structure to be a more 'common' format.
That is change the 'laptops' and 'desktops' tables to have the 'auto_increment' keys. This changes the 'computers' table to have a primary key of 'computer_id' from 'laptops' or 'desktops' and a 'computer_type'.
Here are the table structures and triggers.
It has been tested on mysql 5.5.16 on windows xp.
CREATE TABLE `laptops` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `desktops` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `computers` (
`computer_id` int(11) NOT NULL,
`computer_type` varchar(45) NOT NULL,
PRIMARY KEY (`computer_id`,`computer_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DELIMITER $$
USE `testmysql`$$
DROP TRIGGER /*!50032 IF EXISTS */ `laptop_bins`$$
CREATE
/*!50017 DEFINER = 'test'#'localhost' */
TRIGGER `laptop_bins` AFTER INSERT ON `laptops`
FOR EACH ROW BEGIN
INSERT INTO computers (computer_id, computer_type ) VALUES (new.id, 'laptop');
END;
$$
DELIMITER ;
DELIMITER $$
USE `testmysql`$$
DROP TRIGGER /*!50032 IF EXISTS */ `desktop_bins`$$
CREATE
/*!50017 DEFINER = 'test'#'localhost' */
TRIGGER `desktop_bins` AFTER INSERT ON `desktops`
FOR EACH ROW BEGIN
INSERT INTO computers (computer_id, computer_type ) VALUES (new.id, 'desktop');
END;
$$
DELIMITER ;
Sample Queries and Output:
INSERT INTO laptops (NAME) VALUES ('laptop1');
INSERT INTO desktops (NAME) VALUES ('desktop1');
INSERT INTO laptops (NAME) VALUES ('laptop2');
INSERT INTO desktops (NAME) VALUES ('desktop2');
Laptops:
id name
------ ---------
1 laptop1
2 laptop2
Desktops:
id name
------ ----------
1 desktop1
2 desktop2
Computers:
computer_id computer_type
----------- ---------------
1 desktop
1 laptop
2 desktop
2 laptop
This more a possible approach to the requirement than an answer.
I can create the code if required. It is not a lot of code on top of what is here.
The problem is to maintain tables in an other database, in sync, without doing lots of repeat work.
My suggestion:
In the 'computers' database - have a 'computers_new' table that is inserted to by the 'after insert' trigger and holds the relevant key information. Including a 'unprocessed' column.
I would then run a script at regular intervals or was triggered when the 'computers_new' table changed. It would:
1) transfer the 'unprocessed' details to the 'laptops', 'desktops' tables in the other database.
2) mark the transferred records as processed.
Advantages:
Lots of small chunks of work.
By using transactions it is reliable.
Drawbacks.
Ensuring tables are in sync.