Issue with cursor in MYSQL proceure - mysql

The following procedure works almost perfeclty with one exception. The first select returns two records. However, in the loop it builds three cases as though it goes around three times. Can't figure it out. Something obvious I'm not seeing.
DECLARE DTE DATE;
DECLARE EXIT_LOOP BOOLEAN;
DECLARE DATECURSOR CURSOR FOR
SELECT DISTINCT DATE
FROM SCHEDULE
WHERE BKFST > 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET EXIT_LOOP = TRUE;
OPEN DATECURSOR;
SET #s = '';
DATE_LOOP: LOOP
FETCH DATECURSOR INTO DTE;
SET #s = CONCAT(#s,CONCAT('SUM(CASE WHEN SCHEDULE.DATE =', "'", DTE, "'", ' THEN SCHEDULE.', _TYPE,' END) AS ', "'", DTE ,"', "));
IF EXIT_LOOP THEN
CLOSE DATECURSOR;
LEAVE DATE_LOOP;
END IF;
END LOOP DATE_LOOP;
SET #s = TRIM(trailing ', ' from #s);
SET #q = CONCAT('SELECT MOW_ID, FUNDING, ',#s,' FROM SCHEDULE GROUP BY MOW_ID, FUNDING');
SELECT #q;
PREPARE stmt1 FROM #q;
EXECUTE stmt1;
commit;
DEALLOCATE PREPARE stmt1;

Related

Mysql Error Code: 1329. No data - zero rows fetched, selected, or processed

so i have a store procedure where the function is to find out the column which contains the name expired or end (Datetime type), and after that find out the record for that column which containing 90 days away from now. so I made this store procedure
CREATE DEFINER=`fachry`#`%` PROCEDURE `get_data`()
BEGIN
DECLARE i VARCHAR(100);
DECLARE a VARCHAR(100);
DECLARE cur1 CURSOR FOR SELECT DISTINCT
TABLE_NAME, COLUMN_NAME FROM information_schema.columns WHERE (COLUMN_NAME LIKE 'End%' OR COLUMN_NAME LIKE 'Expired%') AND TABLE_SCHEMA='brambang_uom'
AND TABLE_NAME NOT LIKE 'discount%' ;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO i,a;
-- SELECT i,a; -- printing table name
SET #s = CONCAT('select * from ', i, ' where ', a, ' >= CURDATE() + INTERVAL 90 DAY AND ' , a, ' <
CURDATE() + INTERVAL 91 DAY');
PREPARE stmt1 FROM #s;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END LOOP read_loop;
CLOSE cur1;
END
but idk why it keeps on error
Error Code: 1329. No data - zero rows fetched, selected or processed
You have not declared a handler -
drop procedure if exists p;
delimiter $$
CREATE PROCEDURE p()
BEGIN
DECLARE i VARCHAR(100);
DECLARE a VARCHAR(100);
declare finished int default 1;
DECLARE cur1 CURSOR FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM information_schema.columns
WHERE (COLUMN_NAME LIKE 'End%' OR COLUMN_NAME LIKE 'Expired%')
AND TABLE_SCHEMA='sandbox'
AND TABLE_NAME NOT LIKE 'discount%' ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET FINISHED = 0;
OPEN cur1;
read_loop: LOOP
IF FINISHED = 0 THEN
LEAVE read_loop;
END IF;
FETCH cur1 INTO i,a;
#SELECT i,a; -- printing table name
SET #s = CONCAT('select * from ', i, ' where ', a, ' >= CURDATE() + INTERVAL 90 DAY AND ' , a, ' <
CURDATE() + INTERVAL 91 DAY');
PREPARE stmt1 FROM #s;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
#select #s;
END LOOP read_loop;
CLOSE cur1;
END $$
delimiter ;

MySQL Stored Procedure Cursor example

following code is running fine, what I need to ask how can I use a variable instead of a table name written in cursor select statement?
block5: begin
declare var1 int default 0;
DECLARE done TINYINT DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR SELECT co_srno FROM vu_company where katscode in ('OGDC', 'LUCK', 'MCB');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor1;
my_loop: LOOP
FETCH cursor1 INTO var1;
IF done THEN
LEAVE my_loop;
ELSE
set #s = concat("insert into ", #temp_table_name_scrnr_data, " (sr_no) values (", var1, ")");
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END LOOP;
end block5;

Procedure fails if second call creates other columns

Fellow residents of the Stack Exchange,
I am currently trying to create a procedure that will reformat data in a very major way. I get a list of data on tickets (summary for random months). The input views always have the same columns, but since I have to display it with the months as columns (which are usually entered as a value in the Monat column on the view).
Sooo, after some major research, trial and error and a lot of headaches I got to make it work. The procedure accepts a single ticket-number and 'returns' all stats on that single ticket.
I do this by:
Iterate over each distinct month, building a CREATE TEMPORARY TABLE statement.
Execute that statement, then deallocate the statement
Iterate over each ticket-value, sorting them into the temporary table with a INSERT INTO ON DUPLICATE KEY UPDATE statement (which I build, execute and deallocate each iteration anew)
Again Iterate over each distinct month, building a last update to fill the summary columns (I know, I could combine this into Step 1, but I tried to keep the steps as separate as I could, just to make it easier to read, I can optimize once I'm done making it work as I want).
Select the temporary table, so it's being returned
Clean up some loose ends, because I'm a habitually neat person.
The good thing: It Works!
The bad thing: It works only for one input value. Whenever I change it to another ticket number, that would require different months for columns it fails with an "Error Code 1054, Unknown Column in field list", referring to an old column (month) the current query ought not have.
I can run the procedure as many times as I want, as long as the columns of the temporary table are identical.
This behavior resets, whenever I drop and recreate the procedure or create a new connection.
Obviously, I'm forgetting to do a cleaning step somewhere along the way, and me being fairly new to SQL in general and MySQL in particular probably didn't even know to look for it :(.
Help would be most appreciated, thanks,
Fred
DELIMITER //
CREATE PROCEDURE proc_get_relevant_tickets(bID VARCHAR(10))
DETERMINISTIC
READS SQL DATA
BEGIN
# Declare storage vairables for withdrawing data from view
DECLARE ID, FiID, ZVB, ZNVB, ZGes, WVB, WNVB, WGes INTEGER;
DECLARE Mon VARCHAR(50);
DECLARE RowVerb, RowNVerb, RowGes, Counter INTEGER;
DECLARE verbucht, nichtverbucht, gesamt VARCHAR(50);
DECLARE currentticket INTEGER;
DECLARE statezges, statewges LONGTEXT;
# Declare runtime stuff
DECLARE done INT DEFAULT FALSE;
DECLARE declaration LONGTEXT;
DECLARE temptext VARCHAR(50);
DECLARE Months CURSOR FOR SELECT DISTINCT Monat FROM view_list_of_tickets t WHERE bID = t.ID;
DECLARE `Values` CURSOR FOR SELECT * FROM view_list_of_tickets t WHERE bID = t.ID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
# Clean up in case something interrupted last execution
DROP TEMPORARY TABLE IF EXISTS temp_storage_5437485;
# If there are any entries to work upon
IF (SELECT COUNT(t.ID) FROM view_list_of_tickets t WHERE bID = t.ID > 0)
THEN
# Create temporary table to put the values into
SET declaration = 'CREATE TEMPORARY TABLE `temp_storage_5437485` (ID INTEGER PRIMARY KEY, TicketNr INTEGER, Category VARCHAR(50), ';
SET done = FALSE;
OPEN Months;
read_loop: LOOP
FETCH Months INTO temptext;
IF done THEN
LEAVE read_loop;
END IF;
SET declaration = CONCAT(declaration, '`', temptext, ' Zeit` INTEGER DEFAULT 0, ');
SET declaration = CONCAT(declaration, '`', temptext, ' Wert` INTEGER DEFAULT 0, ');
END LOOP;
CLOSE Months;
SET declaration = CONCAT(declaration, '`Gesamt Zeit` INTEGER, `Gesamt Wert` INTEGER);');
SELECT declaration INTO #declaration;
PREPARE stmt FROM #declaration;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# End of creating the storage container
# Cycle through values and input into temporary table
SET done = FALSE;
SET verbucht = 'Verbucht';
SET nichtverbucht = 'Nicht Verbucht';
SET gesamt = 'Gesamt';
SET currentticket = 0;
SET Counter = 0;
SET RowVerb = 1;
SET RowNVerb = 2;
SET RowGes = 3;
OPEN `Values`;
read_values: LOOP
FETCH `Values` INTO ID, FiID, ZVB, ZNVB, ZGes, WVB, WNVB, WGes, Mon;
IF done THEN
LEAVE read_values;
END IF;
# If a new ticket has been arrived at, increment the counters
IF currentticket > 0 AND ID <> currentticket THEN
SET currentticket = ID;
SET Counter = Counter + 1;
SET RowVerb = RowVerb + 3;
SET RowNVerb = RowNVerb + 3;
SET RowGes = RowGes + 3;
END IF;
IF currentticket = 0 AND ID <> currentticket THEN
SET currentticket = ID;
END IF;
# Insert first (Verbucht) row
SET declaration = CONCAT('INSERT INTO `temp_storage_5437485` (`ID`, `TicketNr`, `', Mon, ' Zeit`, `', Mon, ' Wert`) VALUES (');
SET declaration = CONCAT(declaration, RowVerb, ', ', ID, ', ', ZVB, ', ', WVB, ') ON DUPLICATE KEY UPDATE ');
SET declaration = CONCAT(declaration, '`', Mon, ' Zeit`=', ZVB, ', `', Mon, ' Wert`=', WVB, ';');
SELECT declaration INTO #declaration;
PREPARE stmt FROM #declaration;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Insert second (Nicht Verbucht) row
SET declaration = CONCAT('INSERT INTO `temp_storage_5437485` (`ID`, `TicketNr`, `', Mon, ' Zeit`, `', Mon, ' Wert`) VALUES (');
SET declaration = CONCAT(declaration, RowNVerb, ', ', ID, ', ', ZNVB, ', ', WNVB, ') ON DUPLICATE KEY UPDATE ');
SET declaration = CONCAT(declaration, '`', Mon, ' Zeit`=', ZNVB, ', `', Mon, ' Wert`=', WNVB, ';');
SELECT declaration INTO #declaration;
PREPARE stmt FROM #declaration;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Insert third (Gesamt) row
SET declaration = CONCAT('INSERT INTO `temp_storage_5437485` (`ID`, `TicketNr`, `', Mon, ' Zeit`, `', Mon, ' Wert`) VALUES (');
SET declaration = CONCAT(declaration, RowGes, ', ', ID, ', ', ZGes, ', ', WGes, ') ON DUPLICATE KEY UPDATE ');
SET declaration = CONCAT(declaration, '`', Mon, ' Zeit`=', ZGes, ', `', Mon, ' Wert`=', WGes, ';');
SELECT declaration INTO #declaration;
PREPARE stmt FROM #declaration;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
UPDATE temp_storage_5437485 SET Category = verbucht WHERE temp_storage_5437485.ID = RowVerb LIMIT 5;
UPDATE temp_storage_5437485 SET Category = nichtverbucht WHERE temp_storage_5437485.ID = RowNVerb LIMIT 5;
UPDATE temp_storage_5437485 SET Category = gesamt WHERE temp_storage_5437485.ID = RowGes LIMIT 5;
END LOOP;
CLOSE `Values`;
# End of cycling for values input
# Being calculating the total values
SET declaration = 'UPDATE temp_storage_5437485 SET `Gesamt Zeit` = (';
SET statezges = '';
SET statewges = '';
SET done = FALSE;
OPEN Months;
read_loop: LOOP
FETCH Months INTO temptext;
IF done THEN
LEAVE read_loop;
END IF;
# If not the first entry, add more
IF statezges <> '' THEN
SET statezges = CONCAT(statezges, ' + ');
END IF;
IF statewges <> '' THEN
SET statewges = CONCAT(statewges, ' + ');
END IF;
# Add column name
SET statezges = CONCAT(statezges, 'temp_storage_5437485.`', temptext, ' Zeit`');
SET statewges = CONCAT(statewges, 'temp_storage_5437485.`', temptext, ' Wert`');
END LOOP;
CLOSE Months;
SET declaration = CONCAT(declaration, statezges, '), `Gesamt Wert` = (', statewges, ') LIMIT 100000');
SELECT declaration INTO #declaration;
PREPARE stmt FROM #declaration;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# End calculating the total values
SELECT * FROM temp_storage_5437485;
DROP TEMPORARY TABLE IF EXISTS temp_storage_5437485;
ELSE
SELECT 'is null';
END IF;
DROP TEMPORARY TABLE IF EXISTS temp_storage_5437485;
END //
DELIMITER ;

Pass table name to select statement from cursor

How can I use values returned from Cursor as table names in mysql procedures ?
DECLARE cur CURSOR FOR
select table_name, column_name
from information_schema.columns
where table_schema = 'foo' and table_name like 'bar%';
OPEN cur;
loop1: LOOP
FETCH cur
INTO table_val, column_val;
IF no_more_rows THEN
CLOSE cur;
LEAVE loop1;
END IF;
update table_val SET column_val ...
This throws error that foo.table_val doesnt exist. How can I get the actual table name to be passed to the select statement ?
Change update table_val SET column_val ... into
SET #sql = CONCAT('UPDATE ', table_val, ' SET ', column_val, ' = whatever WHERE...');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Read more about it here.
But note that you can not parameterize table and column names. This only works with values.
I will also share my fix. hope it will help someone too.
-- set to "$$" as we have ";" inside of Procedure. MySQL will be confused.(is this part of Procedure or should I run it now?)
DELIMITER $$
CREATE PROCEDURE UpdateTable()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE _table_name CHAR(255);
DECLARE cur CURSOR FOR
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'db_name' AND table_type = "BASE TABLE";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
My_loop: LOOP
FETCH cur INTO _table_name;
SET #my_table_name = _table_name;
IF done THEN
LEAVE My_loop;
END IF;
SET FOREIGN_KEY_CHECKS = 0;
SET #stmt = CONCAT('ALTER TABLE ', #my_table_name, ' CONVERT TO CHARACTER SET utf8;');
PREPARE stmt1 FROM #stmt;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET FOREIGN_KEY_CHECKS = 1;
END LOOP;
CLOSE cur;
END$$
-- set to normal. ";"
DELIMITER ;

Syntax Error in MySQL stored procedure

The below SP is not giving any result even though there are 48 rows as per the where clause
BEGIN
DECLARE SelectClause VARCHAR(2000);
if v_mode='SearchByString' then
SET SelectClause ='select SURVEY_USER.username,SURVEY.* from SURVEY, SURVEY_USER';
if v_SearchString is not null then
SET SelectClause=CONCAT(#SelectClause,' where ');
Set SelectClause=CONCAT(#SelectClause,v_SearchString);
end if;
SET SelectClause=CONCAT(#SelectClause,' order by SURVEY.created_date DESC;') ;
select SelectClause;
SET #query = SelectClause;
PREPARE stmt FROM #query;
EXECUTE stmt;
select stmt;
end if;
END
I tried a lot but not getting any problem. I also tried select clause to print the command at various places to not able to print it.
Please give me some solution.
There are my parameters that I am passing
v_mode='SearhByString'
v_SearchString='SURVEY_USER.username=chiragfanse'
It should return 48 rows but does not return anything.
BEGIN
DECLARE SelectClause VARCHAR(2000);
IF v_mode = 'SearchString' THEN
SET SelectClause = CONCAT('select SURVEY_USER.username,SURVEY.* from SURVEY, SURVEY_USER');
IF SearchString IS NOT NULL THEN
SET SelectClause = CONCAT(SelectClause, ' where ', SearchString);
END IF;
SET SelectClause = CONCAT(SelectClause, ' order by SURVEY.created_date DESC;');
SET #query = SelectClause;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END
All declaration have to be at the begining.
Rename #SelectClause to SelectClause, because you are declaring this variable.
Check the usage of SET clauses. I have added one.
Have a look at prepared statements reference, it will help you to execute the query you built.
you have wrong concat functions. Try this.
if v_mode='SearchString' then
DECLARE #SelectClause varchar(2000);
SET #SelectClause =CONCAT(select (SURVEY_USER.username,SURVEY.*) from SURVEY, 'SURVEY_USER');
if SearchString is not null then
#SelectClause=CONCAT(#SelectClause, 'where' ,SearchString);
end if;
SET #SelectClause=#SelectClause
order by SURVEY.created_date DESC
execute(#SelectClause)
end if;
try this. let me know if you need anything else.