Syntax Error in MySQL stored procedure - mysql

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.

Related

MySQL Continue Error Handler for missing table when calling PREPARE

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

Issue with cursor in MYSQL proceure

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;

Dynamic table name variable in stored procedure

I want to create a function that will create a unique random id. The parameters will simply be min (the minimum number), max (the maximum number), and tablename (the name of the table to check to see if the id produced by the rand() function already exists).
I have discovered through other posts that you can't pass table names into functions, because functions can't execute dynamic SQL, but you can pass them into stored procedures. I have found numerous examples on StackOverflow of how to pass table names into stored procedures, and they all boil down to using prepared statements.
I have created a stored procedure as shown below:
DELIMITER $$
CREATE DEFINER=`user`#`localhost` PROCEDURE `rand_id`(IN `min` INT, IN `max` INT, IN `tablename` VARCHAR(20) CHARSET utf8, OUT `uid` INT)
BEGIN
DECLARE count_id int;
SET count_id = 1;
SET #s = CONCAT('COUNT(`id`) INTO count_id FROM `', tablename, '` WHERE `id` = ', uid);
WHILE count_id > 0 DO
SET uid = FLOOR(rand() * max + min);
PREPARE stmt from #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END WHILE;
END$$
DELIMITER ;
Whenever I run the following code:
CALL rand_id(1000000000, 9999999999, 'test', #id);
SELECT #id;
I get this error:
#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 'NULL' at line 1
I'm at a loss for what's wrong. I saw somewhere that you can't use user variables inside a stored procedure, but that seems to be incorrect because there are a lot of examples on StackOverflow where the correct solutions do just that.
Sorry for my low level of MySQL understanding. I'm sure my code is fraught with syntax errors and poor design. I appreciate any help I can get. I researched this for quite a while and tried many things but to no avail. The above portion of code is the closest I've been able to get, and yields the least errors, but it's still not working.
Thank you.
EDIT: As per the second example in #Barmar's answer, I changed my code to look like this:
BEGIN
DECLARE count_id int;
SET count_id = 1;
SET #s = CONCAT('SELECT COUNT(`id`) INTO count_id FROM `', tablename, '` WHERE `id` = ?');
PREPARE stmt from #s;
WHILE count_id > 0 DO
SET #uid = FLOOR(rand() * max + min);
EXECUTE stmt USING #uid;
END WHILE;
DEALLOCATE PREPARE stmt;
SET uid = #uid;
END
It seems to have fixed my initial problem but now I get this error:
#1327 - Undeclared variable: count_id
EDIT: Here is my code changed to fit #slaakso's answer, and add in what #Barmar said about using #count_id:
DELIMITER $$
CREATE DEFINER=`mjrinker`#`localhost` PROCEDURE `rand_id`(IN `min` BIGINT, IN `max` BIGINT, IN `tablename` VARCHAR(128) CHARSET utf8, OUT `uid` BIGINT)
BEGIN
SET #count_id = 1;
SET uid = 0;
SET #s = CONCAT('SELECT COUNT(`id`) INTO #count_id FROM `', tablename, '` WHERE `id` = ?');
PREPARE stmt from #s;
WHILE #count_id > 0 DO
SET #uid = FLOOR(rand() * max + min);
EXECUTE stmt USING #uid;
END WHILE;
DEALLOCATE PREPARE stmt;
SET uid = #uid;
END$$
DELIMITER ;
You need to assign #s after you assign the uid variable.
You're also missing the SELECT keyword in your query.
SET #count_id = 1
WHILE #count_id > 0 DO
SET uid = FLOOR(rand() * max + min);
SET #s = CONCAT('SELECT COUNT(`id`) INTO #count_id FROM `', tablename, '` WHERE `id` = ', uid);
PREPARE stmt from #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END WHILE;
But you should actually just prepare the statement once, using a placeholder, which you fill in when using EXECUTE.
SET #count_id = 1
SET #s = CONCAT('SELECT COUNT(`id`) INTO #count_id FROM `', tablename, '` WHERE `id` = ?');
PREPARE stmt from #s;
WHILE #count_id > 0 DO
SET #uid = FLOOR(rand() * max + min);
EXECUTE stmt USING #uid;
END WHILE;
DEALLOCATE PREPARE stmt;
SET uid = #uid;
Note that the parameters to EXECUTE have to be user variables, that's why I changed uid to #uid there. Then we set the output parameter at the end of the loop.
You also need to use a user variable for INTO #count_id.
First of all it is highly unusual to use random numbers as ID's for tables. Mabye you should consider using AUTO_INCREMENT columns.
If you really want to use random numbers, couple of fixes for the code:
You should use value for uid for the first time you run the query
(without it it will be NULL, therefore the error).
You are missing SELECT in your dynamic query
The "INTO count_id" syntax will not work as count_id is not visible inside the dynamic SQL (use #var variable instead)
Your min and max values are declared as INT's, but your passed parameters exceed the INT range (-2147483648 - 2147483647)

SQL Stored Procedure Variable

i am testing this stored procedure thing and i tried using variables,
BEGIN
DECLARE #day int;
SET #day = 1;
IF (1 = 1) THEN
SET #query = 'SELECT #day';
END IF;
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
this works perfectly fine with a different query and without declaring a variable,i know there is something wrong with the variables and i have researched a lot about this and i cant find any answers. i have this error
If you are on SQL-Server, you must declare the variable: #query.
Just got it.
I just need to do SET #day := 1; instead of SET #day = 1;

what is wrong with MySQL select Store Procedure with dynamic query

i have tried to create MySQL store procedure in that i want to make dynamic query.
code on which i working..
DELIMITER $$
DROP PROCEDURE IF EXISTS `test`.`selectp` $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `selectp`(in a_str_Condition varchar(500))
BEGIN
SET #Query = 'SELECT * from test123';
IF a_str_Condition != ''
THEN
SET #strCondition = CONCAT(' WHERE ? ');
SET #param = a_str_Condition;
ELSE
SET #strCondition = ' Order by aaa desc';
END IF
SET #Query = CONCAT(#Query, #strCondition );
PREPARE stmt FROM #Query;
EXECUTE stmt USING #param;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
here i want pass parameter as aaa = 3 and concat it with mysql query, but it show me error as below.
please let me clear on this store procedure. Any help will be Appreciate.
Trying to answer to your ...what is wrong with MySQL select Store Procedure..?
As others mentioned you have ; missing. That only solves a syntax error.
But you have bigger problems with the way you try to construct your query and EXECUTE it:
You're incorrectly trying to treat all where conditions as one parameter with WHERE ?, instead of parameterizing values like WHERE id = ?
In case you don't pass a condition you can't use USING in EXECUTE. It'll fail.
Now since you don't execute your query multiple times, you pass conditions as a string anyway, and it seems that you're more after flexibility than security, IMHO there is no much sense in using parameters here.
That being said a more succinct version of your SP might look like this
DELIMITER $$
CREATE PROCEDURE selectp(IN _conditions VARCHAR(500), IN _orderby VARCHAR(500))
BEGIN
SET #sql = CONCAT(
'SELECT * FROM test123 WHERE 1 = 1',
COALESCE(CONCAT(' AND ', NULLIF(_conditions, '')), ''),
' ORDER BY ',
COALESCE(NULLIF(_orderby, ''), 'id DESC')
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Usage examples:
-- default parameters either with null or an empty string
CALL selectp('', '');
CALL selectp(NULL, NULL);
-- set where conditions
CALL selectp('id IN(1, 3)', NULL);
-- set order by
CALL selectp(NULL, 'col1 DESC, col2');
Here is SQLFiddle demo
You've lost a semicolon after END IF.
And that's what mysql is pointed you to - it always shows you the expression part it couldn't parse. So always look at the code right before the one from the error description.
There should be a semi column after the END IF statement:
ELSE
SET #strCondition = ' Order by aaa desc';
END IF; //add semicolumn here
Before this line:
SET #Query = CONCAT(#Query, #strCondition );