Mysql - How to use user defined variables on pointers - mysql

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

Related

Handling unfound data in mySQL procedure loop

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 ;

Return empty table after rollback

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.

Error Code : 1324 Undefined CURSOR

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;

mysql stored procedure variable error

Hi I am finding my way round MySQL trying to migrate data from MSsql for the first time. I have created a stored procedure that clear all the tables down so I can import the data repeatedly as I test and alter things. I thought I had this pretty well figured but I am unsure how to get the actual value of the variable to go with the delete statement. Thanks for any assistance
DELIMITER $$
CREATE PROCEDURE ClearData ()
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_TableName varchar(100) DEFAULT "";
-- declare cursor for list of tables to clear
DEClARE TableToRemove CURSOR FOR
SELECT TABLE_NAME from information_schema.tables where table_type ='BASE TABLE';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN TableToRemove;
ClearData: LOOP
FETCH TableToRemove INTO v_TableName;
IF v_finished = 1 THEN
LEAVE ClearData;
END IF;
--This is the problem how do I get the value of v_TableName
delete from `v_TableName`;
END LOOP ClearData;
CLOSE TableToRemove;
END$$
DELIMITER ;

Cursor in Procedure does not return any values

I have a database where temp tables are created, those table names are randomly generated and saved in Checkouts.unid. I want to drop all those tables and truncate the table Checkouts. I thought the niftiest solution would be a procedure, but it will not work:
DROP PROCEDURE IF EXISTS `spCheckoutsCleanup`;
CREATE PROCEDURE `spCheckoutsCleanup` ()
SQL SECURITY INVOKER
BEGIN
DECLARE `t` VARCHAR(64);
DECLARE `ch` CURSOR FOR SELECT `unid` FROM `Checkouts`;
OPEN `ch`;
drop_tables: LOOP
FETCH `ch` INTO `t`;
DROP TABLE IF EXISTS `t`;
END LOOP;
CLOSE `ch`;
TRUNCATE TABLE `Checkouts`;
END
I always get "No data - zero rows fetched, selected, or processed" although those tables are there and the table Checkouts is not empty though.
You have to add something like this in order to end your loop:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET ...;
See example in the documentation.. E.g. ...
DROP PROCEDURE IF EXISTS `spCheckoutsCleanup`;
CREATE PROCEDURE `spCheckoutsCleanup` ()
SQL SECURITY INVOKER
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE `t` VARCHAR(64);
DECLARE `ch` CURSOR FOR SELECT `unid` FROM `Checkouts`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN `ch`;
drop_tables: LOOP
FETCH `ch` INTO `t`;
IF done THEN
LEAVE drop_tables;
END IF;
DROP TABLE IF EXISTS `t`;
END LOOP;
CLOSE `ch`;
TRUNCATE TABLE `Checkouts`;
END
Otherwise you will get an error once you reached the end of your cursor.
I got it working with this:
DROP PROCEDURE IF EXISTS `spCheckoutsCleanup`;
CREATE PROCEDURE `spCheckoutsCleanup` ()
SQL SECURITY INVOKER
BEGIN
DECLARE done int DEFAULT 0;
DECLARE t CHAR(64);
DECLARE ch CURSOR FOR SELECT `unid` FROM `Checkouts`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN ch;
drop_table: LOOP
FETCH ch INTO t;
IF done = 1 THEN
LEAVE drop_table;
END IF;
SET #sql := CONCAT('DROP TABLE IF EXISTS `', t, '`');
PREPARE dropt FROM #sql;
EXECUTE dropt;
END LOOP;
CLOSE ch;
TRUNCATE TABLE `Checkouts`;
END;
CALL spCheckoutsCleanup;