Cannot set variable in trigger - mysql

I am trying to set a variable in a trigger that is the most recent entry in the table. However, PHPMyAdmin notes there is an error at line SET clicked_campaign_id =. I do not see the problem here.
CREATE TRIGGER tr_user_action_click
AFTER INSERT ON users_click FOR EACH ROW
BEGIN
DECLARE clicked_campaign_id int
SET clicked_campaign_id =
(SELECT campaignId
FROM users_click
WHERE id = (SELECT max(id) FROM users_click));
Update onlineportal.`campaigns`
SET `clicks` = `clicks` + 1
WHERE id = clicked_campaign_id;
END
Is there a different way to set a variable...?

You must set the DELIMITER in phpMyAdmin, as shown in the image:
Then, create the trigger:
CREATE TRIGGER `tr_user_action_click` AFTER INSERT ON `users_click`
FOR EACH ROW
BEGIN
DECLARE `clicked_campaign_id` INT;
SET `clicked_campaign_id` =
(SELECT `campaignId`
FROM `users_click`
WHERE `id` = (SELECT max(`id`) FROM `users_click`));
UPDATE `onlineportal`.`campaigns`
SET `clicks` = `clicks` + 1
WHERE `id` = `clicked_campaign_id`;
END//

Related

Set update row id to OUT parameter in MySQL

The table tbtable contains the following columns.
The procedure to create or update an entry in tbtable is the following.
CREATE PROCEDURE `createOrUpdateTbTable` (
IN `this_pid` INT UNSIGNED,
IN `this_sid` INT UNSIGNED,
IN `this_ri` LONGBLOB,
IN `this_defaults` TINYINT,
IN `this_approved` TINYINT,
OUT `id` INT UNSIGNED
)
BEGIN
UPDATE `tbtable` SET
`ri` = this_ri, `defaults` = this_defaults, `approved` = this_approved
WHERE `pid` = this_pid AND `sid` = this_sid;
IF ROW_COUNT() = 0
THEN
INSERT INTO `tbtable` (`pid`, `sid`, `ri`, `defaults`, `approved`)
VALUES (this_pid, this_sid, this_ri, this_defaults, this_approved);
SET id = LAST_INSERT_ID();
END IF;
END
Right now I don't have any way to get the id of an entry when an update occurs. To what script should I change my current createOrUpdate method so that I can also retrieve the id when an update happens?
I checked other similar questions but they don't have any OUT parameter, so not applicable for my case.
Thanks.
EDIT:
BEGIN
IF EXISTS (SELECT*FROM `tbtable` WHERE `pid` = this_pid AND `sid` = this_sid)
THEN
UPDATE `tbtable`
SET
`ri` = this_ri, `defaults` = this_defaults, `approved` = this_approved
WHERE `pid` = this_pid AND `sid` = this_sid;
SET id = `id` ;
ELSE
INSERT INTO `tbtable` (`pid`, `sid`, `ri`, `defaults`, `approved`)
VALUES (this_pid, this_sid, this_ri, this_defaults, this_approved);
SET id = LAST_INSERT_ID();
END IF;
END
I tried this approach as well, but the id is null when there is an update.
We could run a SELECT t.myid INTO v_id FROM t WHERE ... statement to store a value into a local procedure variable.
Or, we could set a user-defined variable.
Note that the same identifier might be used for a routine parameter, a local variable and a column. A routine parameter takes precedence over a table column.
In the general case, an UPDATE statement can affect more than one row, so we could have multiple rows. The procedure argument is a scalar, so we would need to decide which of the rows we want to return the id from.
Assuming that id column is guaranteed to be non-NULL in the (unfortunately named) tbtable table...
BEGIN
DECLARE lv_id BIGINT DEFAULT NULL;
-- test if row(s) exist, and fetch lowest id value of from matching rows
SELECT t.id
INTO lv_id -- save retrieved id value into procedure variable
FROM tbtable t
WHERE t.pid = this_pid
AND t.sid = this_sid
ORDER BY t.id
LIMIT 1
;
-- if we got a non-NULL value returned
IF lv_id IS NOT NULL THEN
-- do the update
UPDATE `tbtable` t
SET t.ri = this_ri
, t.defaults = this_defaults
, t.approved = this_approved
WHERE t.pid = this_pid
AND t.sid = this_sid
;
ELSE
INSERT INTO `tbtable` (`pid`, `sid`, `ri`, `defaults`, `approved`)
VALUES (this_pid, this_sid, this_ri, this_defaults, this_approved)
;
SET lv_id = LAST_INSERT_ID();
END IF;
-- set OUT parameter
SET id = lv_id ;
END$$
Note that this procedure is subject to a race condition, with a simultaneous DELETE operation from another session. Our SELECT statement could return an id for a matching row, and another session could DELETE that row, and then our update runs, and doesn't find the row. Timing here is pretty tight, it would be difficult to demonstrate this without adding a delay into the procedure, like a SELECT WAIT(15); right before the UPDATE (to give us fifteen seconds to run a delete from another session.)
You try to return a single value but your update statement could be executed in multiple rows. So when you return the id from that type of updated statement , you need to loop through the updated rows and return any one of those updated row values (because you expect that the combination of pid and sid is unique). Here is sample code without the rid columns as i do not want to create a temporary database with that :)
CREATE PROCEDURE createOrUpdateTbTable (
IN this_pid INT UNSIGNED,
IN this_sid INT UNSIGNED,
IN this_ri LONGBLOB,
IN this_defaults TINYINT,
IN this_approved TINYINT,
OUT id INT UNSIGNED
)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE updated_id INT;
DECLARE updatedIds CURSOR FOR SELECT tbtable.id FROM tbtableWHERE pid = this_pid AND sid = this_sid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
IF EXISTS (SELECT*FROM `tbtable` WHERE `pid` = this_pid AND `sid` = this_sid)
THEN
UPDATE `tbtable`
SET
`defaults` = this_defaults, `approved` = this_approved
WHERE `pid` = this_pid AND `sid` = this_sid;
OPEN updatedIds;
read_loop: LOOP
FETCH updatedIds INTO updated_id;
SET id = updated_id;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE updatedIds;
ELSE
INSERT INTO `tbtable` (`pid`, `sid`, `defaults`, `approved`)
VALUES (this_pid, this_sid, this_defaults, this_approved);
SET id = LAST_INSERT_ID();
END IF;END
You need explicit return the value at the end:
IF ROW_COUNT() = 0
THEN
INSERT INTO `tbplanhassurface` (`planid`, `surfaceid`, `roi`, `defaultsurface`, `approved`)
VALUES (this_planid, this_surfaceid, this_roi, this_defaultsurface, this_approved);
SET id = LAST_INSERT_ID();
ELSE
SELECT #id = your_id_field
FROM `tbplanhassurface`
WHERE `planid` = this_planid
AND `surfaceid` = this_surfaceid;
END IF;
SELECT #id;
END

how to update this stored procedure?

this is my code to update 2 table in stored procedure
DROP PROCEDURE IF EXISTS `SP_ENGG_UPDATE_ITEM_SERVICE`;
DELIMITER $$
CREATE PROCEDURE `SP_ENGG_UPDATE_ITEM_SERVICE`(
IN `p_uid` BIGINT(20) UNSIGNED,
IN `p_sid` BIGINT(20) UNSIGNED,
IN `p_sdid` BIGINT(20) UNSIGNED,
IN `p_mediaJson` TEXT,
IN `p_itemStatus` TINYINT(1),
IN `p_mediavalue` TEXT)
BEGIN
DECLARE stcount int DEFAULT 0;
DECLARE ttcount int DEFAULT 0;
SET #updated = 0;
IF(p_sid > 0 && p_sdid > 0 ) THEN
UPDATE user_service_details SET
p_mediavalue = p_mediaJson,
status = p_itemStatus
WHERE user_service_id = p_sid AND id =p_sdid;
SET stcount = (SELECT count(*) FROM user_service_details WHERE user_service_id = p_sid AND status = 2 );
SET ttcount = (SELECT count(*) FROM user_service_details WHERE user_service_id= p_sid );
IF (stcount = ttcount) THEN
UPDATE user_service SET
status= 4
WHERE id = p_sid AND engg_id = p_uid ;
END IF;
SET #updated = 1;
END IF;
SELECT #updated;
END
this is my query to update
call SP_ENGG_UPDATE_ITEM_SERVICE(252317018022627,25231702221634,252302221637,
'{"images":["img1.png","img2.png","img3.png"],"videos":["vid1.mp4","vid2.mp4","vid3.mp4"],"audios":["aud1.mp3","aud2.mp3","aud3.mp3"]}',2,'before_image');
when I am trying to update this error is showing:-
Error Code: 1054 Unknown column 'p_mediavalue' in 'field list'
Any one have any idea how to update.
The column name user_service_details in Table user_service_details is wrong as per the error thrown "Unknown column name".

SQL trigger after update update next row

I have a table that looks something like this:
Columns:
user_id int(11) PK
module_id int(11) PK
academy_team_id int(11) PK
academy_id int(11) PK
sort_number int(11)
is_complete int(11)
score_to_pass int(11)
is_open int(11)
Now i wish to add a trigger so that when you update this table if the value is_complete is equal to 1 then update the next row's is_open and set it to1
I have attempted with the following trigger sql:
begin
if new.is_complete = 1 then
set next.is_open = 1;
end if ;
end
Sadly this did not work so im not sure how to do it can anyone push me in the right direction?
According to pala_ Answer
im getting the following error when updating my row:
ERROR 1442: 1442: Can't update table 'user_has_academy_module' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
SQL Statement:
UPDATE `system`.`user_has_academy_module` SET `is_complete`='1' WHERE `user_id`='1' and`module_id`='11' and`academy_team_id`='49' and`academy_id`='29'
Your basic trigger body should be something like this:
begin
if new.is_complete = 1 and (select id from <table> where user_id = new.user_id and module_id = new.module_id and academy_team_id = new.academy_team_id sort_number = new.sort_number +1 ) then
update <table> set is_open = 1
where user_id = new.user_id
and academy_team_id = new.academy_team_id
and module_id = new.module_id
and sort_number = new.sort_number + 1;
end if
end
It will check to see if there IS another thing to set open (based on same user_id, academy_team_id and module_id, and next sequential sort_number), and if there is, set it open.
MySQL cant update the same table the trigger is set on. It will need to be done with a stored procedure instead.
delimiter //
create procedure completeandopen(IN param INT)
begin
declare next_id integer;
declare _user_id integer;
declare _module_id integer;
declare _academy_team_id integer;
declare _sort_number integer;
select user_id,
module_id,
academy_team_id,
sort_number
into _user_id,
_module_id,
_academy_team_id,
_sort_number
from tester
where id = param;
update tester set is_complete = 1 where id = param;
select id
into next_id
from tester
where id = param + 1
and user_id = _user_id
and module_id = _module_id
and academy_team_id = _academy_team_id
and sort_number = _sort_number + 1;
if (next_id is not null) then
update tester set is_open = 1 where id = next_id;
end if;
end//
delimiter ;
I think this should work - i haven't tested on your table structure, and it does assume a unique primary key on your table. If it doesn't have that - it's easy enough to modify.
To use it, just call completeandopen(id of the row to be completed) (after changing the table name from tester to your table name)

How to create a mysql trigger to update a column

I want to update a column of new inserted row based on value set in another table.
I have created some thing like this :
BEGIN
DECLARE value float;
DECLARE comission float;
DECLARE c float;
select value=`uc_amount` from inserted;
select comission=`config_value` from fixed_configs WHERE `config_key` = 'deal_comission';
c = value - (value * (comission/100));
update user_credits set `uc_admin_amount`=value;
END
But its shows error
here table structure
user_credit:
uc_amount float(10,2)
uc_admin_amount float(5,2)
uc_created timestamp
uc_extra text
fixed_configs:
config_key varchar(225)
config_value varchar(225)
You basically need 2 triggers one before insert and one before update
The before insert will get the uc_amount and will calculate the uc_admin_amount and before update will check if the old uc_amount is not same as new uc_amount and if so do the calculation.
delimiter //
create trigger ins_user_credit before insert on user_credit
for each row
begin
declare comission float(5,2);
select config_value into comission from fixed_configs WHERE config_key = 'deal_comission';
set new.uc_admin_amount = new.uc_amount - (new.uc_amount * (comission/100));
end; //
delimiter ;
delimiter //
create trigger upd_user_credit before update on user_credit
for each row
begin
declare comission float(5,2);
if(old.uc_amount <> new.uc_amount)
select config_value into comission from fixed_configs WHERE config_key = 'deal_comission';
set new.uc_admin_amount = new.uc_amount - (new.uc_amount * (comission/100));
end if ;
end; //
delimiter ;

Update in mysql trigger not working

I'm creating a trigger to execute after an insert is done into my checkin table but my update statement is not working
DELIMITER $$
DROP TRIGGER IF EXISTS checkins_AINS$$
CREATE TRIGGER `checkins_AINS` AFTER INSERT ON `checkins` FOR EACH ROW
BEGIN
DECLARE client_id INT;
DECLARE duplicate_record INTEGER DEFAULT 0;
DECLARE bpoints INT;
DECLARE business_id INT;
DECLARE CONTINUE HANDLER FOR 1062 SET duplicate_record = 1;
SELECT checkinPoints, id INTO bpoints, business_id FROM businesses WHERE id = new.venue_id;
INSERT INTO clients_checkins_summary(client_id, venue_id, first_checkin, last_checkin,visits)
VALUES(new.client_id, new.venue_id, new.createAt, new.createAt,1);
INSERT INTO clients_points_summary(client_id, business_id,current_points)
VALUES(new.client_id, business_id,bpoints);
IF duplicate_record = 1
THEN
UPDATE clients_checkins_summary
SET last_checkin = new.createAt,
visits = visits + 1
WHERE client_id = new.client_id and venue_id = new.venue_id;
UPDATE clients_points_summary
SET current_points = current_points + bpoints
WHERE client_id = new.client_id and business_id = business_id;
END IF;
END$$
DELIMITER ;
Inserting:
insert into checkins(client_id,venue_id,points,createAt,updateAt)
values (52,19,1,now(),now());
for the first time works fine but when the case of update is trigger is entering into the if but is not update the value.
I trace the variables into a table and all the values are correct but update is not been updating anything.
I missing something?
am I missing something?
Possibly this
UPDATE clients_points_summary
SET current_points = current_points + bpoints
WHERE client_id = new.client_id and business_id = business_id;
The problem here is that your local variable business_id and the column name clients_points_summary.business_id are ambiguous. You could disambiguate as follows:
UPDATE clients_points_summary cps
SET cps.current_points = cps.current_points + bpoints
WHERE cps.client_id = new.client_id and cps.business_id = business_id;