Im writing a procedure, I want it to return table if there wasnt any rollbacks, and return empty table / nothing if there was at least 1 rollback.
DELIMITER $$
CREATE PROCEDURE payment(IN amount int, IN profession varchar(50))
BEGIN
DECLARE done BOOL DEFAULT FALSE;
DECLARE salary INT;
DECLARE pes VARCHAR(11);
DECLARE summary INT DEFAULT 0;
DECLARE employee_cursor CURSOR FOR (SELECT RIGHT(PESEL,3), pensja FROM Pracownicy WHERE zawod=profession);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DROP TEMPORARY TABLE IF EXISTS tmp1;
CREATE TEMPORARY TABLE tmp1(pesel char(11), status varchar(20) DEFAULT 'wyplacono');
SET AUTOCOMMIT =0;
START TRANSACTION;
OPEN employee_cursor;
readLoop : LOOP
FETCH employee_cursor INTO pes,salary;
IF done THEN
LEAVE readLoop;
END IF;
SET summary = summary + salary;
IF( summary > amount ) THEN
ROLLBACK;
END IF;
INSERT INTO tmp1(pesel) VALUES(CONCAT('********',pes));
END LOOP;
CLOSE employee_cursor;
COMMIT;
SELECT * from tmp1;
END $$
DELIMITER ;
As far it works fine when it doesnt rollback, but
INSERT INTO tmp1(pesel) VALUES(CONCAT('********',pes));
seems to ignore transaction :/
move the rollback test to outside the loop.
Related
I am trying to implement a trigger which transfers multiple records from 4 different tables to another set of 4 tables (denoted by the _history suffix) which have the same schema.
The trigger is as follows
DELIMITER //
create trigger shift_to_history
before update on event_ledger
for each row
begin
declare id,event_id,communication_number,communication_flag,slot_number,room_id,status_level,prev_status_level int default 0;
declare msg text;
declare req_date,end_date,start_date date;
declare purpose varchar(30);
declare misc_ledger_cursor cursor for select * from misc_ledger where event_id = old.event_id;
declare resource_communication_cursor cursor for select * from resource_communication where event_id = old.event_id;
declare slots_and_details_cursor cursor for select * from slots_and_details where event_id = old.event_id;
declare event_communication_cursor cursor for select * from event_communication where event_id = old.event_id;
insert into event_ledger_history values(old.event_id,old.event_name,old.description,old.username,old.start_date,old.end_date);
open misc_ledger_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
misc_ledger_transfer: loop
fetch misc_ledger_cursor into event_id,communication_number,req_date,msg,communication_flag;
if finished = 1 then
leave misc_ledger_transfer;
end if;
insert into misc_ledger_history values (event_id,communication_number,req_date,msg,communication_flag);
end loop misc_ledger_transfer;
end;
close misc_ledger_cursor;
delete from misc_ledger where event_id = old.event_id;
open resource_communication_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
resource_coms_transfer: loop
fetch resource_communication_cursor into event_id,msg,communication_number,communication_flag;
if finished = 1 then
leave resource_coms_transfer;
end if;
insert into resource_communication_history values (event_id,msg,communication_number,communication_flag);
delete from resource_communication where id = event_id;
end loop resource_coms_transfer;
end;
close resource_communication_cursor;
open event_communication_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
event_coms_transfer: loop
fetch event_communication_cursor into event_id,msg,communication_number,communication_flag;
if finished = 1 then
leave event_coms_transfer;
end if;
insert into event_communication_history values (event_id,msg,communication_number,communication_flag);
end loop event_coms_transfer;
end;
close event_communication_cursor;
delete from event_communication where event_id = old.event_id;
open slots_and_details_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
slots_and_details_transfer: loop
fetch slots_and_details_cursor into id,event_id,slot_number,room_id,start_date,end_date,status_level,prev_status_level,purpose,msg;
if finished = 1 then
leave slots_and_details_transfer;
end if;
insert into slots_and_details_history values (id,event_id,slot_number,room_id,start_date,end_date,status_level,prev_status_level,purpose,msg);
end loop slots_and_details_transfer;
end;
close slots_and_details_cursor;
delete from slots_and_details where event_id = old.event_id;
end//
DELIMITER ;
The Trigger runs only till
insert into event_ledger_history values(old.event_id,old.event_name,old.description,old.username,old.start_date,old.end_date);
After which it does not do anything.The MySQL Terminal gives a success message but the desired output is not achieved. ie The remaining history tables are till empty (the ones which use the cursor).
I reffered to MySQL stored procedure, handling multiple cursors and query results but did not receive favorable results.
I think I'm narrowing in on my issue. I have a loop that is only firing once:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN fixer_cursor;
REPEAT
FETCH fixer_cursor INTO my_curr_id;
IF NOT done THEN
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END IF;
UNTIL done END REPEAT;
CLOSE fixer_cursor;
END $$
DELIMITER ;
I think the issue may be that inside the IF NOT done THEN loop, I have a few select statements that may be trying to select results that don't exist (not found).
This is fine (for me) as the logic continues along using NULL values in those spots, but I suspect that my CONTINUE HANDLER FOR NOT FOUND is catching the NOT FOUND warning that these selects throw inside the loop and are thus stopping the entire loop prematurely.
How can I listen for NOT FOUND warning on my cursor only?
Or, how can I suppress the NOT FOUND warning in my MAYBE FOUND select statements inside my loop so my loop continues?
I think I have solved the issue by implementing a counter in a loop rather than relying on the NOT FOUND handler:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE my_total INT DEFAULT NULL; -- Declare total
DECLARE my_counter INT DEFAULT 0; -- Declare counter starting at 0
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
OPEN fixer_cursor;
SELECT FOUND_ROWS() INTO my_total; -- Get total number of rows
my_fixerloop: LOOP
FETCH fixer_cursor INTO my_curr_id;
IF my_counter >= my_total THEN -- Compare counter to total
CLOSE fixer_cursor;
LEAVE my_fixerloop;
END IF;
SET my_counter = my_counter + 1; -- Increment by one for each record
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END LOOP;
END $$
DELIMITER ;
I just started learning MySQL and am having trouble compiling a procedure.
It's giving me an error undefined cursor. I looked up a few examples on this forum and corrected my code but it still throws the same error.
DELIMITER $
CREATE PROCEDURE MY_PROC()
BLOCK1: BEGIN
DECLARE LOOP1_DONE BOOLEAN DEFAULT FALSE;
DECLARE VAR_TKR VARCHAR(100) DEFAULT 0;
DECLARE TKR_VALUE VARCHAR(100) DEFAULT 0;
-- OTHER VARIABLE DECLARATIONS
DECLARE CUR1 CURSOR FOR SELECT DISTINCT TKR FROM STG_TBL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET LOOP1_DONE = TRUE;
-- SET VARIABLE VALUES
OPEN CUR1;
CUR1_LOOP: LOOP
FETCH CUR1 INTO VAR_TKR;
IF LOOP1_DONE THEN
CLOSE CUR1;
LEAVE CUR1_LOOP;
END IF;
-- OTHER SELECT STATEMENTS AND CALCULATIONS
BLOCK2: BEGIN
DECLARE LOOP2_DONE BOOLEAN DEFAULT FALSE;
DECLARE CUR1_DATA CURSOR FOR
SELECT TKR_VALUE
FROM STG_VALUE_TBL
WHERE TKR = VAR_TKR
ORDER BY TKR_DATE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET LOOP2_DONE = TRUE;
OPEN CUR1_DATA;
-- SET VARIABLE VALUES
CUR1_DATA_LOOP: LOOP
FETCH CUR1_DATA INTO TKR_VALUE;
IF LOOP2_DONE THEN
CLOSE CUR1_DATA;
LEAVE CUR1_DATA_LOOP;
END IF;
-- OTHER SELECT STATEMENTS AND CALCULATIONS
END LOOP CUR1_DATA_LOOP;
END BLOCK2;
-- CLOSE CUR1_DATA; <removed as not needed>
END LOOP CUR1_LOOP;
-- CLOSE CUR1; <removed as not needed>
END BLOCK1;
$
DELIMITER;
Please find below table and sample data:
CREATE TABLE STG_TBL
(
ID NUMERIC(38),
TKR VARCHAR(10) NOT NULL
);
INSERT INTO STG_TBL VALUES (100000,'TKR1');
INSERT INTO STG_TBL VALUES (200000,'TKR2');
INSERT INTO STG_TBL VALUES (300000,'TKR3');
COMMIT;
CREATE TABLE STG_VALUE_TBL
(
TKR_DATE DATE,
TKR VARCHAR(10),
TKR_VALUE DECIMAL(20,10),
ADDED_DATE DATE
);
INSERT INTO STG_VALUE_TBL VALUES ('01-01-2015','TKR1','10.231','01-30-2016');
INSERT INTO STG_VALUE_TBL VALUES ('01-02-2015','TKR1','18.151','01-30-2016');
INSERT INTO STG_VALUE_TBL VALUES ('01-03-2015','TKR1','22.952','01-30-2016');
COMMIT;
I´m new to InnoDB and starting with transactions. I´ve been 24 hours trying to get this to work.
I´m creating an exchange site and really need a transaction to be made. First, make a Select and find some data, and then some updates and inserts according with the results given.
I won´t post the full query as it might be very complicated to read so I created a new query to point out whats bothering.
Table Log
CREATE TABLE `log` (
`num_rows` int(10) unsigned NOT NULL,
`new_value` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Stored Procedure
DROP PROCEDURE IF EXISTS `test`//
CREATE PROCEDURE `test` (IN var1 BIGINT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE result INT;
DECLARE num_rows INT;
DECLARE cur1 CURSOR FOR
SELECT #var1 := #var1 +1 AS result;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
START TRANSACTION;
OPEN cur1;
SELECT FOUND_ROWS() into num_rows;
INSERT INTO log (num_rows,new_value) VALUES (num_rows,var1);
read_loop:
LOOP
FETCH cur1 INTO result;
IF done = 1 THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
CLOSE cur1;
COMMIT;
END//
When I try
CALL test(1);
Im passing 1 as var1 parameter. So in cur1, the value should be increased. And later insert a new row to the log with the new value. It looks like := asignment isn´t working.
I actually changed
SELECT #var1 := #var1 +1 AS result;
for this
SELECT var1 := var1 +1 AS result;
And get an error on ":= var1 +1"
I understand that the code of the question is an abstraction of the actual code of the stored procedure, so do not quite understand what you need to do, however, a code like this can be helpful.
/* Procedure structure for procedure `test` */
/*!50003 DROP PROCEDURE IF EXISTS `test` */;
DELIMITER $$
CREATE PROCEDURE `test`(IN `var1` BIGINT)
BEGIN
DECLARE `done` TINYINT(1) DEFAULT 0;
DECLARE `result` BIGINT;
DECLARE `_num_rows` INT;
DECLARE `cur1` CURSOR FOR
SELECT SQL_CALC_FOUND_ROWS #`var1` := `var1` + 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET `done` := 1;
START TRANSACTION;
OPEN `cur1`;
SET `var1` := #`var1`;
SELECT FOUND_ROWS() INTO `_num_rows`;
INSERT INTO `log` (`num_rows`, `new_value`) VALUES (`_num_rows`, `var1`);
`read_loop`: LOOP
FETCH `cur1` INTO `result`;
IF (`done`) THEN
LEAVE `read_loop`;
END IF;
END LOOP `read_loop`;
CLOSE `cur1`;
COMMIT;
END$$
DELIMITER ;
It is important to indicate the difference between 9.4. User-Defined Variables and routine parameters 13.1.15. CREATE PROCEDURE and CREATE FUNCTION Syntax, are different variables.
SQL Fiddle demo
I have a stored proc which inserts rows from a view with ranks into a temporary table.
The temp table is created before I run a cursor loop that inserted values, and SELECT'ed after the loop is done.
However when I CALL medianMessagesPerWeek(); I get an "Error Code : 1329 No data - zero rows fetched, selected, or processed."
If I create the table as a MYISAM table I can manually select the table and confirm that data has been inserted but the stored proc will still give me nothing.
Am I missing something here?
DELIMITER $$
USE `yongopal_metrics`$$
DROP PROCEDURE IF EXISTS `medianMessagesPerWeek`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `medianMessagesPerWeek`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tempJoinWeek, tempActiveWeek, rank INT DEFAULT 0;
DECLARE joinWeek, activeWeek, memberNo, messages INT;
DECLARE cur CURSOR FOR SELECT * FROM cohortMessagesPerMemberPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
CREATE TEMPORARY TABLE medianMessagesPerWeek
(
joinWeek INT,
activeWeek INT,
memberNo INT,
messages INT,
rank INT
) ENGINE=MEMORY;
OPEN cur;
read_loop: LOOP
FETCH cur INTO joinWeek, activeWeek, memberNo, messages;
IF done THEN
LEAVE read_loop;
END IF;
IF tempJoinWeek = joinWeek AND tempActiveWeek = activeWeek THEN
SET rank = rank + 1;
ELSE
SET tempJoinWeek = joinWeek;
SET tempActiveWeek = activeWeek;
SET rank = 1;
END IF;
INSERT INTO medianMessagesPerWeek VALUES (joinWeek, activeWeek, memberNo, messages, rank);
END LOOP;
CLOSE cur;
SELECT * FROM medianMessagesPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
END$$
DELIMITER ;
EDIT
here is what cohortMessagesPerMemberPerWeek looks like
DELIMITER $$
USE `yongopal_metrics`$$
DROP VIEW IF EXISTS `cohortMessagesPerMemberPerWeek`$$
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost` SQL SECURITY DEFINER VIEW `cohortMessagesPerMemberPerWeek` AS
SELECT
WEEK(`m`.`regDatetime`,0) AS `joinWeek`,
WEEK(`cd`.`sendDate`,0) AS `activeWeek`,
`m`.`memberNo` AS `memberNo`,
COUNT(0) AS `messages`
FROM (`yongopal`.`chatData` `cd`
JOIN `yongopal`.`members` `m`
ON ((`cd`.`sender` = `m`.`memberNo`)))
GROUP BY WEEK(`m`.`regDatetime`,0),WEEK(`cd`.`sendDate`,0),`m`.`memberNo`
ORDER BY WEEK(`m`.`regDatetime`,0),WEEK(`cd`.`sendDate`,0)$$
DELIMITER ;
Looks like you're missing a not found handler for your cur cursor. This is necessary to set your done boolean to true when the fetch statement no longer returns any rows (and hence you have reached the end of the dataset returned by the cursor declaration).
Give this a try:
DELIMITER $$
USE `yongopal_metrics`$$
DROP PROCEDURE IF EXISTS `medianMessagesPerWeek`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `medianMessagesPerWeek`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tempJoinWeek, tempActiveWeek, rank INT DEFAULT 0;
DECLARE joinWeek, activeWeek, memberNo, messages INT;
DECLARE cur CURSOR FOR SELECT * FROM cohortMessagesPerMemberPerWeek;
declare continue handler for not found set done := true;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
CREATE TEMPORARY TABLE medianMessagesPerWeek
(
joinWeek INT,
activeWeek INT,
memberNo INT,
messages INT,
rank INT
) ENGINE=MEMORY;
OPEN cur;
read_loop: LOOP
FETCH cur INTO joinWeek, activeWeek, memberNo, messages;
IF done THEN
LEAVE read_loop;
END IF;
IF tempJoinWeek = joinWeek AND tempActiveWeek = activeWeek THEN
SET rank = rank + 1;
ELSE
SET tempJoinWeek = joinWeek;
SET tempActiveWeek = activeWeek;
SET rank = 1;
END IF;
INSERT INTO medianMessagesPerWeek VALUES (joinWeek, activeWeek, memberNo, messages, rank);
END LOOP;
CLOSE cur;
SELECT * FROM medianMessagesPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
END$$
DELIMITER ;