问题
I've created a stored procedure to return a value for row count of any table I pass in as an "IN" parameter, and output that rowcount to an OUT parameter
PROCEDURE `GetCount`(in tblname varchar(255), out rowcount int)
BEGIN
SET @sql_text1 = concat('SELECT COUNT(*) FROM ',tblname);
SET @sql_text2 = concat(@sql_text1,' INTO ');
SET @sql_final = concat(@sql_text2, rowcount);
PREPARE stmt1 FROM @sql_text1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END
when I open a query window in MySQL workbench and do the following:
set @tablename = 'my_table_name;
set @cnt = -9998;
call GetCount(@tablename,@cnt);
SELECT @cnt;
the value of @cnt is NULL.
Is my method of testing the stored proc incorrect, or is the stored proc to blame?
回答1:
Your test methodology is valid, but you have made three errors in the procedure.
Error #1 you are using the wrong variable for the prepared statement.
PREPARE stmt1 FROM @sql_text1;
This should have been...
PREPARE stmt1 FROM @sql_final;
Error #2 This doesn't do what you intend:
SET @sql_final = concat(@sql_text2, rowcount);
This concatenates the value of @sql_text2
with the value of rowcount
. Since rowcount
is an out
parameter, it is null at this point. If any argument to CONCAT()
is null, then the result is also null, so you are actually setting @sql_final
to null. If not for error #1, either the PREPARE
or subsequent EXECUTE
would have thrown an error about ...the right syntax to use near NULL at line 1
.
Here's what you actually intended, the literal string 'rowcount':
SET @sql_final = concat(@sql_text2, 'rowcount');
...but that would also fail, because rowcount
is a program variable. Prepared statements run with session scope, not program scope, so program variables are out of scope in a prepared statement.
The fix requires you to use a user-defined variable, which has session scope, and then copy it into the program variable, as @nbk illustrated in their answer.
SET @sql_final = concat(@sql_text2, '@rowcount');
PREPARE stmt1 FROM @sql_text1;
EXECUTE stmt1;
SET rowcount = @rowcount;
Note that program variables like rowcount
and user-defined variables like @rowcount
are from completely different namespaces, so there's no need for the names to be the same and no need for the names to be different.
Error #3 is not strictly an error, in the sense that it isn't stopping your code from working, but here's a note about a potentially dangerous practice.
You are accepting a table name as input, which opens up a security vulnerability called SQL Injection, where malicious input can cause unexpected/unauthorized results. Even if the argument can be made that this input comes from a trusted source, that argument is disregarded as a matter of best practice, because future changes could invalidate that assumption. It is worth your time to learn to do this, and do it consistently so that it becomes second-nature to you.
You can safely escape a table name, column name, or other object identifier in MySQL by replacing any embedded backtick with a double backtick, then prepending and appending a single backtick on each end.
You can do this at the top of the procedure...
SET tblname = CONCAT('`',REPLACE(tblname,'`','``'),'`');
...or inline...
SET @sql_text1 = concat('SELECT COUNT(*) FROM ',CONCAT('`',REPLACE(tblname,'`','``'),'`'));
...but of course not both. In the second example, the nested CONCAT()
isn't strictly necessary, so this would also work, but the intention is less obvious:
SET @sql_text1 = concat('SELECT COUNT(*) FROM ','`',REPLACE(tblname,'`','``'),'`');
回答2:
Use this stored procdure:
DELIMITER //
DROP PROCEDURE IF EXISTS GetCount //
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetCount`(IN tblname varchar(255), OUT rowcount int)
BEGIN
SET @sql_text1 = concat('SELECT COUNT(*) FROM ',tblname);
SET @sql_text1 = concat(@sql_text1,' INTO ');
SET @sql_text1 = concat(@sql_text1, ' @rowcount;' );
PREPARE stmt1 FROM @sql_text1;
EXECUTE stmt1;
Set rowcount = @rowcount;
DEALLOCATE PREPARE stmt1;
END
//
DELIMITER ;
The idea is that mysql stores the count into the sessionvariable @rowcount which will be created automatically. The rest is simple getting the result to the proper variable.
来源:https://stackoverflow.com/questions/57828895/out-parameter-of-mysql-stored-procedure-is-null-after-calling-stored-procedure