MySQL Continue Error Handler for missing table when calling PREPARE - mysql

In my stored procedure I am calling PREPARE for multiple INSERT IGNORE INTO statements from one database to another, but there is a chance that they dont have the same tables. So all I want to do is to skip that SQL statement and continue to next one if table doesnt exist, i.e. after the PREPARE statement fails.
This is my code:
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.currentYear SET year = YEAR(now()) + 1;');
PREPARE stmt FROM #ins;
EXECUTE stmt;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.table1 SELECT * FROM table1;');
PREPARE stmt FROM #ins;
EXECUTE stmt;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.table2 SELECT * FROM table2;');
PREPARE stmt FROM #ins;
EXECUTE stmt;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.table3 SELECT * FROM table3;');
PREPARE stmt FROM #ins;
EXECUTE stmt;
and so on.. more than 100 of these statements. So when one of these raises an exception "table doesn't exists" I want to ignore that error and continue to the next statement and so on down the line. How can I achieve that?
Thank you in advance!

I've found a solution and it's actually pretty simple. First step is to declare a CONTINUE HANDLER FOR 1146 (mySQL error code for "Table doesn't exist") Then set a variable to TRUE when it gets the error code (1146). Next step is to simply use If statement before EXECUTE to ask if the variable is set to TRUE or FALSE. If FALSE, EXECUTE stmt. Before each PREPARE statement we need to set our variable to FALSE, in case it was triggered by CONTINUE HANDLER and set to TRUE.
Here is the example code:
DECLARE CONTINUE HANDLER FOR 1146 SET #error = TRUE;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.currentYear SET year = YEAR(now()) + 1;');
SET #error = FALSE;
PREPARE stmt FROM #ins;
IF #error = FALSE THEN EXECUTE stmt; END IF;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.table1 SELECT * FROM table1;');
SET #error = FALSE;
PREPARE stmt FROM #ins;
IF #error = FALSE THEN EXECUTE stmt; END IF;
SET #ins = CONCAT('INSERT IGNORE INTO ', databaseName, '.table1 SELECT * FROM table1;');
SET #error = FALSE;
PREPARE stmt FROM #ins;
IF #error = FALSE THEN EXECUTE stmt; END IF; etc.
This way we are able to change or add insert statements (for new tables) to our procedure without getting an error if the table doesn't exist in targeted database. Still to be tested further but it gets the job done for now. I hope someone will find this answer useful. Cheers!

You opened and do not close one of the quotes in your sql

Related

MYSQL - Execute procedure to execute statement from table

I am working in a stored procedure that is fetching queries from a table and execute them.
The problem is that I have some queries with single/doubled quotes and it is throwing an error on execute them.
Procedure
delimiter $$
drop procedure if exists run_change_ids_queries$$
create procedure run_change_ids_queries()
begin
declare s_query TEXT;
declare done bool default false;
declare c_queries cursor for
select `query` from `queries` WHERE `executed` = 0 ORDER BY `qry_id` ASC;
declare continue handler for not found set done = true;
open c_queries;
read_loop: loop
fetch c_queries into s_query;
if done then
leave read_loop;
end if;
-- run the query
set #sql = s_query;
prepare stmt from #sql;
execute stmt;
deallocate prepare stmt;
-- update executed flag on query
set #update = CONCAT('UPDATE `queries` SET `executed` = 1 WHERE `query` LIKE \'',#sql,'\';');
prepare stmt from #update;
execute stmt;
deallocate prepare stmt;
end loop;
end$$
Query update urisegments as s inner join change_product_ids as p on concat('{"product_id":"', p.old_id, '"}') = s.primary_key_value set s.primary_key_value = CONCAT('{"product_id":', p.new_id, '"}') where s.app_namespace = 'Shop' and s.primary_key_value like '%product_id%'; is throwing error: [42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '{"product_id":"', p.old_id, '"}') = s.primary_key_value set s.primary_key_value ' at line 1
Workaround #01
I already tried to escape single/doubled quotes into \' and \" respectively, but it throws another error:
[42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'{\"product_id\":\"\', p.old_id, \'\"}\') = s.primary_key_value set s.primary_k' at line 1.
Don't try to concatenate the query into the SQL. Prepared statements can contain placeholders, which you fill in when you use the EXECUTE statement.
set #update = 'UPDATE `queries` SET `executed` = 1 WHERE `query` = ?');
prepare stmt from #update;
execute stmt USING #sql;
The statement is not escaped.
All single/doubled quotes should be escaped.
update urisegments as s
inner join change_product_ids as p on concat(\'{\"product_id\":\"\', p.old_id, \'\"}\') = s.primary_key_value
set s.primary_key_value = CONCAT(\'{\"product_id\":\', p.new_id, \'\"}\')
where s.app_namespace = \'Shop\' and s.primary_key_value like \'%product_id%\';
Instead of testing for the query, test for its id:
... WHERE qry_id = ?
(Add that column to the initial SELECT.)

single quotes in stored procedure update MYSQL

I'm trying a simple update using a stored proc using data from a web service but it is failing saying Unknown column 'USERNAME' in 'field list' due to the single quotes not being recognised in the stored proc.
BEGIN
UPDATE PYBUsers set IsMember = 1 where user = p_user;
END
as you can see the p_user is supplied but the web service and does not have single quotes so gets rejected. I have also tried
SET #query = CONCAT('UPDATE PYBUsers set IsMember = 1 where user = \'', p_user, '''');
and
SET #query = CONCAT('UPDATE PYBUsers set IsMember = 1 where user = ', "'",p_user,"'");
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt
but no luck. is there an easy solution that I'm missing?
Try
SET #query = CONCAT('UPDATE PYBUsers set IsMember = 1 where user = ''',p_user,'''');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt
To add a single quotes into a string you have to put two single quotes together i.e.
'This is Dan''s string; Single quote is inserted between the n and s
''''; this one is a little awkward to read, but here goes. The first quote opens the string, the next two quotes generate a single quote in the string. The final quote closes the string.
INSERT INTO myTable values ('''')
The above would result in one quote being stored in the table

MYSQL get row count of update from prepared statement in a stored procedure

OK I have this code in a stored procedure:
SET #qry = CONCAT('UPDATE ', usermeta_table, ' SET meta_value = ', #token_count, ' WHERE user_id = ', #temp_id, ' AND meta_key = "token_count"');
PREPARE stmt FROM #qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #did_update = (SELECT ROW_COUNT());
IF #did_update = 0 THEN
SET #qry = CONCAT('INSERT INTO ', usermeta_table, '(user_id, meta_key, meta_value) VALUES (', #temp_id, ', "token_count", ', #token_count, ')');
PREPARE stmt FROM #qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
What I'm after is if the update doesn't update any rows then make a row in the table.
For some reason when I run the above code did_update is always coming back as 0 so the insert aways happens even if the update has updated some rows. How do I fix this to work?
UPDATE: I've just realised that if the values don't change in the update despite the rows existing it returns zero rows. This is what is causing my logic to break...
According to this site,
"you can use ROW_COUNT() with prepared statements, but you need to call it after EXECUTE, not after DEALLOCATE PREPARE, because the row count for allocate prepare is always 0."

how to create MYSQL prepare statements and resetting them in 1 stored procedure

I currently am looping through a list of userNames from the DB. as such :
DECLARE
cur1 CURSOR FOR
select user_name
from users
where user_type = 'SP'
and active = 'Y';
OPEN cur1;
read_loop : LOOP
FETCH cur1 INTO userName;
Now for each userName, i am creating tables with data. Obviously, within the above LOOP, i have multiple PREPARE statements like :
set l_table_name = concat("tmp_rec_",userName);
set l_select_cnt = concat("SELECT count(1) into #l_cnt
from information_schema.tables
where table_schema = 'greptlat_db'
and table_name = '", l_table_name, "'");
PREPARE stmt2 FROM #l_select_cnt;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
if l_cnt > 0 then
set droptable = concat("drop table ", l_table_name);
PREPARE stmt1 FROM #droptable;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END IF;
I have more PREPARE statements that build the data that i want and inserts it into the table that i create for each user.
Now because this is in a LOOP, for each user, i have read that PREPARE statements are global. Which means, the above code, "PREPARE stmt1 FROM #droptable", stmt1 will never change even though it gors through the LOOP for each user. Even if i DEALLOCATE it, it still remains for that stored procedure.
How can i reset this stmt1,stmt2,stmt3 ...etc for each time the LOOP starts again ?
Basically l_table_name will change for each time the LOOP goes through, but stmt1 doesnt change.. I need stmt1 to change so that it will use the new l_table_name everytime
Normally a prepare statement deallocated implicitly before the new statement is prepared. So what is the result if you remove DEALLOCATE PREPARE stmt1;. Did you check the '#droptable' value in each loop?

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.