I want to check the existance of specific record in db table, if it's exist then update if not I want to add new record
I am using stored procedures to do so, First I make update stetement and want to check if it occurs and return 0 then there's no record affected by update statement and that means the record does not exist.
I make like this
DELIMITER //
CREATE PROCEDURE revokePrivilegeFromUsers(IN userId int(11), IN privilegeId int(11), IN deletedBy int(11))
BEGIN
DECLARE isExist int;
isExist = update `user_privileges` set `mode` ='d' ,`updated_by` = deletedBy, `date_time_assigned` = CURRENT_TIMESTAMP() where `user_id`= userId and `privilege_id`=privilegeId;
IF isExist == 0 THEN
insert into `user_privileges`(`user_id`,`privilege_id`,`mode`,`date_time_assigned`,`updated_by`)values (userId ,privilegeId ,'d',CURRENT_TIMESTAMP(),deletedBy );
END IF;
END //
DELIMITER ;
This error occur with me
#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 '= update `user_privileges` set `mode` ='d' ,`updated_by` = deletedBy, `date_time' at line 6
Is the way I am working is supported by mysql?
I solve the problem, I had 2 prblems
ROW_COUNT() is used to get the number of rows affected in insert, update or delete statements.
Equals comparison in stored procedure is = not ==
The correct stored procedure is
DELIMITER //
CREATE PROCEDURE revokePrivilegeFromUsers(IN userId int(11), IN privilegeId int(11), IN deletedBy int(11))
BEGIN
DECLARE count int default -1;
update `user_privileges` set `mode` ='d' ,`updated_by` = deletedBy, `date_time_assigned` = CURRENT_TIMESTAMP() where `user_id`= userId and `privilege_id`=privilegeId;
SELECT ROW_COUNT() into count ;
IF count = 0 THEN
insert into `user_privileges`(`user_id`,`privilege_id`,`mode`,`date_time_assigned`,`updated_by`)values (userId ,privilegeId ,'d',CURRENT_TIMESTAMP(),deletedBy );
END IF;
END //
DELIMITER ;
Use the INSERT IGNORE statement instead. I assume that your table has (user_id, privilege_id) as a unique key.
insert ignore into user_privileges (user_id,privilege_id,`mode,date_time_assigned,updated_by)
values (userId ,privilegeId ,'d',CURRENT_TIMESTAMP(),deletedBy )
on duplicate key update mode='d', date_time_assigned=now(),updated_by=deletedBy
Related
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;
...
I have a table in which I want to perform an UPDATE. My problem is that the update changes the primary keys and may produce an error because of the collision, eg: I want to update keys to go from 1-15 to 1-16, and 1-16 exists, so error arises
I know how to do it via PHP, but I only need UPDATE if there is no collision, and DELETE the old row and cancel UPDATE if a collision may occur. So I decided to use a trigger because I see it really clean, eg: if I want to UPDATE 1-15 to 1-16, and 1-16 exists, delete 1-15 and abort UPDATE. This is the trigger I'm trying to create:
CREATE TRIGGER table_trigger BEFORE UPDATE ON table
FOR EACH ROW
BEGIN
IF ( SELECT COUNT(1) FROM table WHERE item_id = NEW.item_id AND related_id = NEW.related_id ) THEN
DELETE FROM table WHERE item_id = OLD.item_id AND related_id = OLD.related_id;
ROLLBACK TRANSACTION;
END IF;
END;//
But is giving back an MySQL error:
SQL 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
which is the DELETE line. I have not so much knowledge about triggers, how can I achieve it what I'm trying? Am I on the right way?
OP's comment:
I use ROLLBACK TRANSACTION to try to abort the update
As per documentation on Triggers (even functions) can't use explicit commit/rollback. It is not permitted.
The trigger cannot use statements that explicitly or implicitly begin or end a transaction, such as START TRANSACTION, COMMIT, or ROLLBACK.
If you don't want to update not be executed on a condition matching, you better throw an error. It won't let the update happen.
Example:
delimiter //
drop trigger if exists table_trigger //
CREATE TRIGGER table_trigger BEFORE UPDATE ON table
FOR EACH ROW
BEGIN
declare rowCount int default 0;
declare error_message varchar(1024) default '';
SELECT COUNT(1) into rowCount FROM table
WHERE item_id = NEW.item_id
AND related_id = NEW.related_id ;
IF ( rowCount > 0 ) THEN -- if( rowCount ) -- too works
-- DELETE FROM table
-- WHERE item_id = OLD.item_id
-- AND related_id = OLD.related_id;
-- ROLLBACK TRANSACTION; -- this is not allowed
set error_message =
concat( error_message, 'Update not allowed for ' );
set error_message =
concat( error_message, 'combination \'item_id=' );
set error_message =
concat( error_message, NEW.item_id, '\' and ');
set error_message =
concat( error_message, '\'related_id=', NEW.related_id, '\'' );
-- throw the error
-- Update not allowed for combination
-- 'itemid=1' and 'related_id=5' ( example )
signal sqlstate 23000 set message_text = error_message;
END IF;
END;//
delimiter ;
I'm doing a table where I store the last time the users do login/logout. Just one row storing an Id, the action as a bit field and the moment as a DATETIME. My idea is to do a stored procedure to make an insert when the user is new and an update when the user exists. I've done this code:
DELIMITER $$
CREATE PROCEDURE sp_LastAction(in id_in int, accion_in bit)
begin
SELECT #CONT:= IdUsuario FROM login WHERE IdUsuario = id_in;
IF NOT #CONT then
INSERT INTO login(IdUsuario, Fecha, Accion)
values (id_in, NOW(), accion_in);
ELSE
UPDATE login SET Fecha = NOW(), Accion = accion_in
WHERE IdUsuario = id_in LIMIT 1;
end IF;
end$$
DELIMITER ;
But when I call the procedure it doesn't do anything, just returns the variable as a void field.
You can make a UPSERT.
CREATE PROCEDURE `sp_LastAction`(id_in int, accion_in bit)
BEGIN
INSERT INTO `login` (`idusuario`, `fecha`, `accion`) VALUES (id_in, now(), accion_in)
ON DUPLICATE KEY UPDATE `fecha` = now(), `accion` = accion_in;
END //
Here's an example: SQL Fiddle
I want to return error message when duplicate records occur, groupName is unique field in group table.
I make like this, how can I make error handleing whithout using mysql-get-diagnostics because the server I am working on is version 5.0.77-log.
DELIMITER //
CREATE PROCEDURE addNewGroup(IN groupName varchar(128), IN addedBy INT,OUT message varchar(128) )
BEGIN
insert IGNORE into `group`( `group_name`,`Date_time_ added`,`added_by`) values (groupName ,CURRENT_TIMESTAMP(),addedBy) ;
END //
DELIMITER ;
I want to return error message when duplication occur?
Try this method -
BEGIN
INSERT IGNORE INTO table VALUES...;
IF ROW_COUNT() = 0 THEN
SET message = 'duplicate records occur';
END IF;
END
ROW_COUNT() function returns the number of inserted rows for the last statement.
In MySQL 5.5. you can use SIGNAL statement to generate a warning.
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