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!
Related
i created an event that execute one time per month. Three tables are important here, Cuota(fee), Alumno(studient) and CuotaxAlumno(fee per studient).
My objective is create a row in table Cuota(fee) one time per month and then with that fee create a payment row for every studient (in table CuotaxAlumno).
I having syntax error in te FETCH line, line 19, and i don't find the problem. i will appreciate the help.
IS WORKING NOW. CODE UPDATED 13-04-2017 Thanks!
DELIMITER $$
CREATE PROCEDURE crearCuotas()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE referenciaMonto INT;
DECLARE referenciaAlumno INT;
DECLARE referenciaCuota INT;
DECLARE fecha DATE;
DECLARE cursorAlumno CURSOR FOR SELECT idAlumno FROM alumno WHERE idEstado=1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET referenciaMonto = (SELECT idMontoCuota FROM montocuota ORDER BY idMontoCuota DESC LIMIT 1);
SET fecha = CURDATE();
INSERT INTO cuota (idMontoCuota, fecha) VALUES(referenciaMonto, fecha);
SET referenciaCuota = (SELECT idCuota FROM cuota ORDER BY idCuota DESC LIMIT 1);
OPEN cursorAlumno;
fetch_loop: LOOP
FETCH cursorAlumno INTO referenciaAlumno;
IF done THEN
LEAVE fetch_loop;
END IF;
INSERT INTO cuotaxalumno(idAlumno, idCuota, idEstado) VALUES(referenciaAlumno, referenciaCuota, 5);
END LOOP;
CLOSE cursorAlumno;
END;
DELIMITER ;
You need to add a loop label:
CREATE PROCEDURE crearCuotas()
BEGIN
/* yada */
OPEN cursorAlumno;
fetch_loop: LOOP
FETCH cursorAlumno INTO referenciaAlumno;
IF done THEN
LEAVE fetch_loop;
END IF;
INSERT INTO cuotaxalumno (idAlumno, idCuota, idEstado)
VALUES (referenciaAlumno, referenciaCuota, 5);
END LOOP;
CLOSE cursorAlumno;
END;
This is because while the label is not required for creating a loop, it is required for the leave statement.
I have used a cursor in MySQL but it always runs one more time then I expect.
Code like this:
drop PROCEDURE if exists test_sp;
DELIMITER //
CREATE PROCEDURE test_sp()
BEGIN
DECLARE varid int;
DECLARE varExit_loop BOOLEAN;
DECLARE cursor_name CURSOR FOR
SELECT id
FROM test;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET varExit_loop = TRUE;
drop table if exists test;
create table test
(id int);
insert into test
values
(1),
(2),
(3);
OPEN cursor_name;
test_loop: LOOP
FETCH cursor_name INTO varid;
select varid;
IF varExit_loop THEN
CLOSE cursor_name;
LEAVE test_loop;
END IF;
END LOOP test_loop;
END; //
DELIMITER ;
After I run the SP, it will return 4 results, 1,2,3 and one more 3.
Is there any way to avoid having one more 3?
I have moved
IF varExit_loop THEN
CLOSE cursor_name;
LEAVE test_loop;
END IF;
END LOOP test_loop;
right under
FETCH cursor_name INTO varid;
and it worked fine.
My question might be simple for you, if you're used to MySQL. I'm used to PostgreSQL SGBD and I'm trying to translate a PL/PgSQL script to MySQL.
Here is what I have :
delimiter //
CREATE TRIGGER pgl_new_user
AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE m_user_team_id integer;
SELECT id INTO m_user_team_id FROM user_teams WHERE name = "pgl_reporters";
DECLARE m_projects_id integer;
DECLARE cur CURSOR FOR SELECT project_id FROM user_team_project_relationships WHERE user_team_id = m_user_team_id;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO m_projects_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO users_projects (user_id, project_id, created_at, updated_at, project_access)
VALUES (NEW.id, m_projects_id, now(), now(), 20);
END LOOP;
CLOSE cur;
END//
But MySQL Workbench gives me an error on DECLARE m_projects_id. I don't really understand because I've the same instruction two lines above...
Any hints ?
EDIT: neubert solved this error. Thanks.
But yet, when I try to insert into users :
Error Code: 1329. No data - zero rows fetched, selected, or processed
Do you have any idea ? Or better, do you know how I can get a better error message ?
All DECLAREs need to be at the top. ie.
delimiter //
CREATE TRIGGER pgl_new_user
AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE m_user_team_id integer;
DECLARE m_projects_id integer;
DECLARE cur CURSOR FOR SELECT project_id FROM user_team_project_relationships WHERE user_team_id = m_user_team_id;
SET #m_user_team_id := (SELECT id FROM user_teams WHERE name = "pgl_reporters");
OPEN cur;
ins_loop: LOOP
FETCH cur INTO m_projects_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO users_projects (user_id, project_id, created_at, updated_at, project_access)
VALUES (NEW.id, m_projects_id, now(), now(), 20);
END LOOP;
CLOSE cur;
END//
Agree with neubert about the DECLARE statements, this will fix syntax error. But I would suggest you to avoid using openning cursors, they may be slow.
For your task: use INSERT...SELECT statement which will help you to copy data from one table to another using only one query.
INSERT ... SELECT Syntax.
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 ;
Iam Using following code to run this event using
IF CURRENT_TIME() = '23:50:00'
But doing so, every second it has to compare the time with server time. can we implement this with out if condistion
drop event OEAuditEvent;
DELIMITER $$
CREATE EVENT OEAuditEvent
ON SCHEDULE EVERY 1 SECOND
STARTS '2012-08-30 09:00:10'
DO
BEGIN
DECLARE a CHAR(20);
DECLARE b,c,d INT;
DECLARE done INT DEFAULT FALSE;
IF CURRENT_TIME() = '23:50:00' THEN
begin
DECLARE cur CURSOR FOR select OE_User,count(OE_User) from RNCM_Status where date(OE_Date)=CURDATE() group by OE_User;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO a, b;
SET c=ceil((b*5)/100);
insert into test values(a,b);
IF done THEN
LEAVE read_loop;
ELSE
insert into OE_Audit(MDN,CAF,UploadedDate,OEUser,OEDate,UserCount,QCCount,intime) select MDN,CAF,UploadedDate,OE_User,OE_Date,b,c,now() from RNCM_Status where OE_User=a and date(OE_Date)=CURDATE() order by rand() limit c;
END IF;
END LOOP;
CLOSE cur;
end ;
END IF;
END $$
DELIMITER ;
Why exactly not create the event itself to run daily at 23:00 and remove IF completely?
CREATE EVENT OEAuditEvent
ON SCHEDULE EVERY 1 DAY
STARTS '2012-08-30 23:00:00'