1615 Error: Prepared statement needs to be re-prepared in MySQL - mysql

I have following stored procedure which was executing perfectly. But since morning I am getting the error
Prepared statement needs to be re-prepared
I tried all the things but could not get any help.
CREATE PROCEDURE `SP_FEEDBACK_REPORT`(
IN p_eventID INT(10),
IN p_sessionID INT(10)
)
BEGIN
SET SESSION group_concat_max_len = 10240;
SET #sqlQry = NULL;
SELECT GROUP_CONCAT(DISTINCT CONCAT(' MAX( IF(attended_id = ', attended_id, ', IF(answer_id !=47, (SELECT key_value FROM tblrating_master WHERE key_id=answer_id), comments),NULL)) AS ', attendee_name)) INTO #sqlQry FROM vwfeedback_report WHERE event_id=p_eventID AND session_id=p_sessionID;
SET #sqlQry = CONCAT('SELECT question, ', #sqlQry, ' FROM vwfeedback_report WHERE event_id=', p_eventID,' AND session_id=', p_sessionID,' GROUP BY feedback_id;');
-- SELECT #sqlQry FROM DUAL;
PREPARE stmt FROM #sqlQry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET SESSION group_concat_max_len = 1024;
END;
Please help

Related

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)

how to get the current value for any column in my sql

I have a procedure where i need to check the current value every time in the another query
SET #sql = NULL;
set #ct=(select count(alloc_hrs) from emp_sample where week(alloc_date)=<current_value>);
SET SESSION group_concat_max_len = 1000000;
SELECT GROUP_CONCAT(DISTINCT
(CONCAT ('MAX(CASE WHEN alloc_date=''',
alloc_date,
''' THEN #ct END) `',
year(alloc_date),week(alloc_date),
'week`'
))
)
INTO #sql
FROM emp_sample;
SET #sql = CONCAT('SELECT emp_code, ', #sql,' FROM emp_sample group by emp_code');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Is there any function like this() in mysql
If not what should I replace to get that

Getting unknown column id on stored procedure call

I have following stored procedure to reset auto increments for a table that gets many inserts and deletes.
DROP PROCEDURE IF EXISTS reset_autoincrement;
DELIMITER $$;
CREATE PROCEDURE reset_autoincrement(IN tableName VARCHAR(250))
BEGIN
SELECT #max := MAX(`id`) + 1 + concat(' FROM ', tableName );
set #alter_statement = concat('ALTER TABLE ', tableName ,' AUTO_INCREMENT = ', #max);
PREPARE stmt FROM #alter_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$;
and call it with
call reset_autoincrement('queueIn');
and get
23:18:25 call reset_autoincrement('queueIn') Error Code: 1054. Unknown column 'id' in 'field list' 0,042 sec
A little excerpt of the table's columns:
id bigint(19) UN AI PK
created_at timestamp
updated_at timestamp
I have two questions.
Obviously ... why do I get this error - the column clearly is there.
The id column gets incremented to a million within 6 hours, there are many insert/delete operations throughout the day. Is there an even better way to reset auto_increments in mysql?
Because you are trying to make it a dynamic query (the below line) and as it stands currently it's a mixture of dynamic and normal query.
SELECT #max := MAX(`id`) + 1 + concat(' FROM ', tableName );
You should make it a dynamic query fully
SET #sql = "SELECT MAX(`id`) + 1 FROM " + tableName;
You would need to hold the variable from first dynamic query and use it in ALTER statement. Something like below
DELIMITER $$;
CREATE PROCEDURE reset_autoincrement(IN tableName VARCHAR(250))
BEGIN
SET #var1 = 0;
SET #sql = "SELECT MAX(`id`) + 1 INTO #var1 FROM " + tableName;
PREPARE stmt FROM #sql;
EXECUTE stmt;
SET #ID = #var1;
set #alter_statement = concat('ALTER TABLE ', tableName ,' AUTO_INCREMENT = ', #ID);
PREPARE stmt FROM #alter_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$;

Stored procedure output variable

I am trying to run a procedure that takes a parameter 'table' for the query, and result as the output parameter. However, it shows as undeclared variable: result
I have doubled checked that no spelling mistake but still have no idea how it happened. Would someone please provide some help or guidance
CREATE DEFINER=`root`#`localhost` PROCEDURE `Function`(IN table varchar(10), OUT result varchar (10))
BEGIN
SET #q = CONCAT ('
Select `field` from `',table,'` into result limit 1;');
PREPARE stmt from #q;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Try:
...
-- SET #q = CONCAT ('Select `field` from `',table,'` into result limit 1;');
SET #`q` := CONCAT('SELECT `der`.`field`
FROM (SELECT `field` FROM `', `table`, '` LIMIT 1) `der`,
(SELECT #`result` := NULL) `init`
INTO #`result`;');
PREPARE `stmt` from #`q`;
EXECUTE `stmt`;
SET `result` := #`result`;
DEALLOCATE PREPARE `stmt`;
...
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

procedure for comparing results of two sql statements

1)Below is the code I'm trying for a procedure where I need to compare the count from two different tables. (tbl1 and tbl2 are in parameters to be passed).
But in the above code the values for 'a' and 'b' are set as statements. I need the resultant value(count) from the two statements to compare in the 'IF' condition.
declare a integer;
declare b integer;
set #a:=concat('select count(*) from ', tbl1);
/*PREPARE stmt1 FROM #a;
execute stmt1;
deallocate PREPARE stmt1;*/
set #b:= concat('select count(*) from ', tbl2);
/*PREPARE stmt2 FROM #b;
execute stmt2;
deallocate PREPARE stmt2;*/
if
#a=#b
then
select 1;
else
select 2;
end if;
2) Actually where I am facing a problem to set 'tbl1' and 'tbl2' as parameters in procedure.
The below code works fine if the table names are given directly, but i need them as parameters.
CREATE PROCEDURE myproc (in tbl1 varchar(50), in tbl2 varchar(50))
declare a integer;
declare b integer;
set #a:=(select count(*) from tbl1);
/*PREPARE stmt1 FROM #a;
execute stmt1;
deallocate PREPARE stmt1;*/
set #b:= (select count(*) from tbl2);
/*PREPARE stmt2 FROM #b;
execute stmt2;
deallocate PREPARE stmt2;*/
if
#a=#b
then
select 1;
else
select 2;
end if;
Hope anyone out there can help me with the solution.
As mentioned in the comments above, it is likely that you shouldn't be doing this at all... but, for what it's worth:
SET #sql := CONCAT('SELECT (
SELECT COUNT(*) FROM `',REPLACE('`','``',tbl1),'`
) = (
SELECT COUNT(*) FROM `',REPLACE('`','``',tbl2),'`
);');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #sql := NULL;
REPLACE() has been used to try and avoid SQL injection (it's somewhat crude, but it's the best one can do without further information).