MySQL Trigger Insert After with Select query from different table - mysql

new to DBA thanks for bearing with me.
Overview:
I have Groups, Subgroups and Users.
User can be owner of Group so should be Owner of all its subgroups
User can be collaborator or follower of group so should be collaborator or follower of all its subgroups
User can be collaborator or follower of just subgroup
Tables are as follow (simplified):
Group(topic_id,title)
Subgroup (subtopic_id,title,topic_id)
rel_Group (user_id,topic_id,type)
//To Determine relationship of user to Group (Owner,Collaborator or Follower)
rel_Subgroup (user_id,subtopic_id,type)
//To Determine relationship of user to Subgroup (Owner,Collaborator or Follower)
User (user_id)
I want to create a trigger when a subgroup is created that will INSERT / UPDATE / DELETE rows in rel_Subgroup so users who are Owner, Collaborator or follower on group with respectively be Owner, Collaborator or follower on subgroup
This is the closest i got but am still getting:
#1415 - Not allowed to return a result set from a trigger.
SQL Query
delimiter //
create trigger Transfer_Rights_to_Subgroup
after insert
on Subgroup
for each row
begin
select user_id,type from rel_Group where rel_Group.topic_id = NEW.topic_id;
insert into rel_Subgroup VALUES (rel_Group.user_id,NEW.subtopic_id,rel_Group.type);
END; //
delimiter ;
I am hoping to sort the insert and then will figure out the update/delete.
Any help, much appreciated!
thx

Managed to solve it:
DROP TRIGGER IF EXISTS Transfer_Rights_to_Subgroup;
DELIMITER //
CREATE TRIGGER Transfer_Rights_to_Subgroup AFTER INSERT ON subgroup
FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE c1 INT;
DECLARE c2 INT;
DECLARE cur CURSOR FOR SELECT User_ID,Type FROM rel_group WHERE rel_group.Topic_ID = NEW.Topic_ID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO c1,c2;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO rel_Subgroup VALUES (c1,NEW.Subtopic_ID,c2);
END LOOP;
CLOSE cur;
END; //
DELIMITER ;

Try this one:
delimiter //
create trigger Transfer_Rights_to_Subgroup
after insert
on Subgroup
for each row
begin
select user_id,type into #userid, #type from group where rel_Group.topic_id = NEW.topic_id;
insert into rel_Subgroup VALUES (#userid,NEW.subtopic_id,#type);
END; //
delimiter ;

Related

MYSQL select into multiple rows

I have this trigger where it checks a table named auctions for auctions that have ended. Once the auction ends, a winner is placed into the column. The trigger then checks whether there is a valid winner. The problem is when its checking the auctions tab and one person has won 2 bids or more. It says resulting row has more than one columns, which makes sense because the person won 2 or more rows. My question is how I can use SELECT INTO to insert multiple rows with the same "winner".
DELIMITER ;
DELIMITER $$
CREATE TRIGGER notify_winner
AFTER UPDATE ON Auctions
FOR EACH ROW
BEGIN
SELECT A.winner, A.vin INTO #buyer, #vin
FROM Auctions AS A WHERE A.winner != 'NONE' AND A.winner IS NOT NULL;
INSERT INTO Wins (winner,vin)
values (#buyer, #vin);
END$$
DELIMITER ;
Actually you can't. Select Into is used when has just one row as result. Use cursor instead. For example:
DELIMITER $$
CREATE TRIGGER notify_winner
AFTER UPDATE ON Auctions
FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cur1 CURSOR FOR
SELECT A.winner, A.vin
FROM Auctions AS A
WHERE A.winner != 'NONE'
AND A.winner IS NOT NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO #buyer, #vin;
IF done THEN
LEAVE read_loop;
END IF;
INSERT
INTO Wins (winner,vin)
values (#buyer, #vin);
END LOOP;
CLOSE cur1;
END$$
DELIMITER ;
For more information take a look at this link: https://dev.mysql.com/doc/refman/5.7/en/cursors.html
Hope it helps!

Mysql multiple table sync

I have two tables from Xenforo:
xf_user
xf_user_authenticate
Table xf_user stores all the info of a user except password hashes, which are stored in xf_user_authenticate.
Both tables have the same column called user_id.
When data is inserted into xf_user_authenticate I need to get the user_id from the new inserted row, then use that user_id to get the username from xf_user and set its value to xf_user_authenticate.
I tried this code, but it doesn't work:
CREATE TRIGGER name_sync AFTER INSERT ON xf_user_authenticate
begin
SELECT 'username' INTO #username FROM xenforo.xf_user WHERE 'user_id'=NEW.user_id;
UPDATE xenforo.xf_user_authenticate SET 'username' = #username;
end
You have few syntax related issues, in addition you are trying to update the same table where you have after insert trigger. You may need to change the trigger to before insert as
delimiter //
create trigger name_sync before insert on xf_user_authenticate
for each row
begin
declare user_name_sel varchar(100);
select user_name into user_name_sel
from xf_user
where user_id = NEW.user_id;
set new.username = user_name_sel;
end;//
delimiter ;
CREATE TRIGGER name_sync BEFORE INSERT ON xf_user_authenticate
BEGIN
DECLARE cUsername VARCHAR(255);
SELECT username INTO cUsername FROM xenforo.xf_user WHERE user_id=NEW.user_id;
SET NEW.username = cUsername;
END

Avoid firing trigger by another trigger in MYSQL

my problem is as follows:
Table A contains list of "Tasks"
Table B contains "TaskProgress" - just an information about time spent on task, user ID, task ID and note
On table A (Tasks), I have trigger, which updates datetime of last change - column DateChanged (intended to capture datetime of edits made by user)
On table B (TaskProgress) I have trigger, which updates total time spent on a task (sum all times for given Task_ID and update column TotalTime in table A)
I wish to update DateChanged in Table A only when user mades the update (which is every time except when trigger on table B updates TotalTime)
So I wonder, whether there is a way how to tell the database not to fire TRIGGER when updating the values in another trigger.
/* set date of last change and date od closing of task */
DELIMITER $$
CREATE TRIGGER before_tasks_update
BEFORE UPDATE ON tasks
FOR EACH ROW BEGIN
SET new.DateChanged = NOW();
IF new.Status_ID = 3 THEN
SET new.DateClosed = NOW();
END IF;
END$$
DELIMITER ;
/* set total time spent on task */
DELIMITER $$
CREATE TRIGGER after_taskprogress_insert
AFTER INSERT ON taskprogress
FOR EACH ROW BEGIN
DECLARE sumtime TIME;
SET #sumtime := (SELECT SEC_TO_TIME( SUM( TIME_TO_SEC( `timeSpent` ) ) )
FROM taskprogress WHERE Task_ID = new.Task_ID);
UPDATE `tasks` SET TimeReal = #sumtime WHERE ID = new.Task_ID;
END $$
DELIMITER ;
I use MySQL 5.5.40
Thanks, zbynek
Add a check to verify that the update implies a new TimeReal value,since only the second trigger updates that column.
DELIMITER $$
CREATE TRIGGER before_tasks_update
BEFORE UPDATE ON tasks
FOR EACH ROW BEGIN
IF new.TimeReal=old.TimeReal THEN SET new.DateChanged = NOW();
END IF;
IF new.TimeReal=old.TimeReal AND new.Status_ID = 3 THEN
SET new.DateClosed = NOW();
END IF;
END$$
DELIMITER ;

Trigger not working as expected

I trying execute an trigger on mysql database.
The command executes successfully, but the trigger not working.
DELIMITER #
CREATE TRIGGER generate_coupon AFTER INSERT ON order
FOR EACH ROW
BEGIN
DECLARE userid, couponvalue INT;
DECLARE couponcode VARCHAR;
SELECT idUser INTO userid FROM indication WHERE email = NEW.email;
SET couponvalue = 20;
SET couponcode = 'abc123';
INSERT INTO coupon(idUser,idOrder,couponvalue,couponcode) values(userid, NEW.id, couponvalue, couponcode);
END#
DELIMITER ;
I suspect your problem arises from the collisions between your variables couponvalue and couponcode with the same-named columns in your coupon table. As documented under Local Variable Scope and Resolution:
A local variable should not have the same name as a table column.
You could simplify your trigger to the following and, in so doing, avoid this problem entirely:
CREATE TRIGGER generate_coupon AFTER INSERT ON order FOR EACH ROW
INSERT INTO coupon
(idUser, idOrder, couponvalue, couponcode)
SELECT idUser, NEW.id, 20, 'abc123'
FROM indication
WHERE email = NEW.email
;

Why do I get duplicate record inserted only at the last record?

I get a duplicate record from my procedure which inserts 330+ records.
But ONLY on the very last record. So in other words the last 2 records are not distinct, they are the same. What is it about this procedure that allows the last record to get duplicated.
DELIMITER $$
DROP PROCEDURE IF EXISTS `zzExclude_Products` $$
CREATE DEFINER=`root`#`%` PROCEDURE `zzExclude_Products`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE VAR_ENTITY_ID VARCHAR(50);
DECLARE CUR_NO CURSOR FOR
SELECT DISTINCT NO
FROM stage_product_data.ITEMMAST AS IM
JOIN stage_product_data.zzLive_Products AS LIVE ON IM.NO = LIVE.SKU
WHERE DIVISION = '30' AND STATUS NOT IN ('XX','YY','ZZ');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN CUR_NO;
REPEAT
FETCH CUR_NO INTO VAR_ENTITY_ID;
INSERT INTO zz_CATALOG (TYPE, ENTITY_ID, ESTRICTION_TYPE, RESTRICTION_VALUE)
VALUES ('Product', VAR_ENTITY_ID, 'Country', 'ALL');
UNTIL done END REPEAT;
CLOSE CUR_NO;
END $$
DELIMITER ;
There's really no need for a cursor here. This can be done in a single INSERT statement.
INSERT INTO zz_CATALOG
(TYPE, ENTITY_ID, ESTRICTION_TYPE, RESTRICTION_VALUE)
SELECT DISTINCT 'Product', EDPNO, 'Country', 'ALL'
FROM stage_product_data.ITEMMAST AS IM
JOIN stage_product_data.zzLive_Products AS LIVE
ON IM.EDPNO = LIVE.SKU
WHERE DIVISION = '30'
AND STATUS NOT IN ('XX','YY','ZZ');
Are you sure it is the procedure and not duplicates in the data you are inserting?