I'm trying to write a trigger to solve innodb auto_increment problem. I want to make orderID is auto_increment however innodb does not allow me. Here is ORDER table
CREATE TABLE IF NOT EXISTS `ORDER` (
`placeID` INT UNSIGNED NOT NULL,
`orderID` INT UNSIGNED NOT NULL,
`userID` INT UNSIGNED NOT NULL ,
`tableNum` SMALLINT NOT NULL,
`orderStatus` TINYINT NOT NULL,
`orderDate` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`placeID`,`orderID`),
FOREIGN KEY (`userID`) REFERENCES `USER` (`userID`),
FOREIGN KEY (`placeID`) REFERENCES `PLACE` (`placeID`))
ENGINE=InnoDB;
Here is the trigger
delimiter $$
DROP TRIGGER /*!50032 IF EXISTS */ `ORDER_TRIGGER` $$
CREATE TRIGGER `ORDER_TRIGGER` BEFORE INSERT ON `ORDER`
FOR EACH ROW
BEGIN
DECLARE orderID INT UNSIGNED;
SELECT MAX(`orderID`) INTO orderID FROM `ORDER` WHERE `placeID` = NEW.placeID;
IF orderID IS NULL THEN
orderID = 1;
END IF;
SET NEW.orderID = orderID+1;
END;
$$
delimiter;
When I execute this script I get this 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 '= 1;
END IF;
SET NEW.orderID = orderID+1;
END' at line 7
Can anybody help me? I looked at google but I can't find accurate solution.
I found my mistake. This is right code.
delimiter $$
DROP TRIGGER /*!50032 IF EXISTS */ `ORDER_TRIGGER` $$
CREATE TRIGGER `ORDER_TRIGGER` BEFORE INSERT ON `ORDER`
FOR EACH ROW
BEGIN
DECLARE orderID INT UNSIGNED;
SELECT MAX(`ORDER`.`orderID`) AS ID INTO orderID FROM `ORDER` WHERE `ORDER`.`placeID` = NEW.placeID;
IF orderID IS NULL THEN
SET orderID = 0;
END IF;
SET NEW.orderID = orderID+1;
END;
$$
Related
Challenge:
Create a method to set "auto_increment" values for tables in a non-sequential way.
The goal is to override the "auto_increment" mechanism and allow the function "LAST_INSERT_ID()" to continue working as expected (returning an INT), so that no changes are needed in software side.
My Solution
The method I found is based on an auxiliary table (unique_id), that stores values available to be assigned. Values are then selected randomly, and removed from the tables as used. When the table gets empty, a new set of ID's is created.
This example is working as expected, but with one problem.
Tables for the demo:
CREATE TABLE `unique_id` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=100;
CREATE TABLE `test_unique_id` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
Defined a stored procedure and a function:
DELIMITER $$
DROP PROCEDURE IF EXISTS `UNIQUE_ID_REFILL`$$
CREATE PROCEDURE UNIQUE_ID_REFILL()
BEGIN
DECLARE a INT Default 0 ;
simple_loop: LOOP
SET a=a+1;
INSERT INTO unique_id (id) values(null);
IF a=100 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$
DROP FUNCTION IF EXISTS `UNIQUE_ID_GET`$$
CREATE FUNCTION UNIQUE_ID_GET()
RETURNS INT(11)
MODIFIES SQL DATA
BEGIN
DECLARE new_id INT(11);
DECLARE unique_id_count INT(11);
SET new_id = 0;
SELECT COUNT(*) INTO unique_id_count FROM unique_id;
IF unique_id_count=0 THEN
CALL UNIQUE_ID_REFILL();
END IF;
SELECT id INTO new_id FROM unique_id ORDER BY RAND() LIMIT 1;
DELETE FROM unique_id WHERE id = new_id;
RETURN new_id;
END $$
Created a Trigger on the destination table (test_unique_id):
CREATE TRIGGER test_unique_id__unique_id BEFORE INSERT ON test_unique_id
FOR EACH ROW
SET NEW.id = UNIQUE_ID_GET();
The solution is getting the random ID's as expected:
INSERT INTO test_unique_id(name) VALUES ('A'),('B'),('C');
Creates the rows:
id name
154 'A'
129 'B'
173 'C'
The Problem
The main problem is that LAST_INSERT_ID() stops working... and the software side is broken:
SELECT LAST_INSERT_ID();
0
Any ideas on how to solve this problem? or any other different approach to the challenge?
Thank you very much.
create table tbl_order_detail(
o_detail_id int NOT NULL AUTO_INCREMENT,
o_id int NOT NULL,
p_id int NOT NULL,
user_qty int NOT NULL,
total int NOT NULL,
primary key(o_detail_id),
foreign key(o_id) references tbl_order(o_id),**strong text**
foreign key(p_id) references tbl_product(p_id));
------------------------------------------------------------------------------
create procedure user_buy_item1(o_id int,pid int,user_qty int,total int)
begin
DECLARE total_products INT DEFAULT 0;
DECLARE new_total INT DEFAULT 0;
insert into tbl_order_detail values(null,o_id,pid,user_qty,total);
select p_qty into total_products from tbl_product where p_id = pid;
set new_total = total_products - user_qty;
update tbl_product set p_qty = new_total where p_id = pid;
end
Error
SQL query:
create procedure user_buy_item1(o_id int,pid int,user_qty int,total int)
begin
DECLARE total_products INT DEFAULT 0
MySQL said: Documentation
#1064 - 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 '' at line 3 **
try this change your insert query
insert into tbl_order_detail(o_id,p_id , user_qty, total ) values(o_id,pid,user_qty,total);
I have a problem with my trigger code.
After I wrote my trigger I wrote Insert to test the trigger. But my Insert gets error as
Error Code:1109. Unknown table employees in field list.
If I put the insert before the trigger-everything works perfect. But I want this Insert to test the trigger.
drop database if exists kontrolno;
create database kontrolno;
use kontrolno;
CREATE TABLE departments(
id TINYINT UNSIGNED PRIMARY KEY,
name CHAR(12) NOT NULL,
min_salary SMALLINT UNSIGNED NOT NULL,
max_salary SMALLINT UNSIGNED NOT NULL
) ENGINE=InnoDB;
CREATE TABLE employees(
id SMALLINT UNSIGNED PRIMARY KEY,
name VARCHAR(255) NOT NULL,
salary SMALLINT UNSIGNED NOT NULL,
department_id TINYINT UNSIGNED,
constraint FOREIGN KEY (department_id)
REFERENCES departments(id)
) ENGINE=InnoDB;
insert into departments(id,name,min_salary,max_salary)
values(1,"qa", 800,2000),
(2,"jd",1200,3500);
DROP TRIGGER if exists checkSalary;
delimiter |
create trigger checkSalary before Insert on employees
for each row
begin
if(employees.salary>max_salary OR employees.salary<min_salary)
then signal sqlstate '45000' set MESSAGE_TEXT="the salary is not valide";
end if;
end;
|
delimiter ;
insert into employees(id,name,salary,department_id)
values(1,"ivan", 200,1);
You had mistakes in your trigger code.
The trigger code should be:
DROP TRIGGER if exists checkSalary;
delimiter |
create trigger checkSalary before Insert on employees
for each row
begin
if(new.salary>(select max_salary from departments where id=new.department_id)
OR
new.salary<(select min_salary from departments where id=new.department_id) )
then signal sqlstate '45000' set MESSAGE_TEXT="the salary is not valid";
end if;
end;
|
delimiter ;
I had a mysql trigger that has been working, I exported it and removed it and am trying to put it back, but I keep running into the following 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 12
My trigger is:
CREATE TRIGGER `accounts_tracking` AFTER UPDATE ON `accounts`
FOR EACH ROW BEGIN
IF( NEW.`check_level` != OLD.`check_level` ) THEN
INSERT INTO `accounts_tracking` ( `change_type`, `account_id`, `field`, `old_int`, `new_int`, `old_time`, `new_time` )
VALUES
( "1",
OLD.id,
"check_level",
OLD.`check_level`,
NEW.`check_level`,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP());
END IF;
END
Line #12 is the 2nd UNIX_TIMESTAMP()
My table structure is as follows:
CREATE TABLE `accounts_tracking` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`change_type` smallint(5) unsigned NOT NULL,
`account_id` int(10) unsigned NOT NULL,
`field` varchar(255) NOT NULL,
`old_int` int(11) NOT NULL,
`new_int` int(11) NOT NULL,
`new_time` int(10) unsigned NOT NULL,
`old_time` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Server type: MySQL
Server version: 5.1.73-log
Thanks.
As barranka suggested in comments section, you need to enclose this trigger in a delimiter, like so:
DELIMITER $$
CREATE TRIGGER `accounts_tracking` AFTER UPDATE ON `accounts`
FOR EACH ROW BEGIN
IF( NEW.`check_level` != OLD.`check_level`) THEN
INSERT INTO `accounts_tracking` ( `change_type`, `account_id`, `field`, `old_int`, `new_int`, `old_time`, `new_time` )
VALUES
( "1",
OLD.id,
"check_level",
OLD.`check_level`,
NEW.`check_level`,
UNIX_TIMESTAMP(),
UNIX_TIMESTAMP());
END IF;
END$$
DELIMITER ;
The reason is that by adding a Begin and End to the statement you are essentially creating a stored routine/procedure with the trigger itself. In order to run multiple statements, like in stored routine/procedure, you need to add delimiters.
In other cases where you do not have the Begin and End within the trigger, you do not need the delimiters. For Example:
CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
CREATE TRIGGER ins_sum BEFORE INSERT ON account FOR EACH ROW SET #sum = #sum + NEW.amount;
I'm trying to add a trigger for auditing to initialize a datetime field on an insert. Does anyone see what might be causing this trigger to not fire???
USE example;
CREATE TABLE USERS (
ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
FULLNAME VARCHAR(128) NOT NULL,
`PASSWORD` CHAR(88) NOT NULL,
EMAIL VARCHAR(128) NOT NULL,
FLAGS TINYINT UNSIGNED DEFAULT 0,
CREATED DATETIME,
UPDATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE INDEX(EMAIL),
PRIMARY KEY( ID )
);
DELIMITER $$;
CREATE TRIGGER USER_T BEFORE INSERT ON USERS FOR EACH ROW
BEGIN
SET NEW.CREATED = CURRENT_TIMESTAMP();
END;$$
DELIMITER ;
INSERT INTO USERS(FULLNAME, `PASSWORD`, EMAIL) VALUES('Admin', 'sQnzu7wkTrgkQZF+0G1hi5AI3Qmzvv0bXgc5THBqi7mAsdd4Xll27ASbRt9fEyavWi6m0QP9B8lThf+rDKy8hg==', 'root#localhost');
It looks like you are using the ; as a delimiter here
SET NEW.CREATED = CURRENT_TIMESTAMP();
END;$$
DELIMITER ;
Try this:
DELIMITER $$;
CREATE TRIGGER USER_T BEFORE INSERT ON USERS FOR EACH ROW
BEGIN
SET NEW.CREATED = CURRENT_TIMESTAMP();
END $$
DELIMITER ;