Creating Dynamic Query in Stored Procedure MySQL - mysql

I have a Table and Rows in table like below
CREATE TABLE Areas(AreaName VARCHAR(255),
PinCode VARCHAR(255))
INSERT INTO Areas(AreaName, PinCode)
VALUES('Teynampet', '6000018'),
('Ramapuram', '6000089'),
('TNagar', '6000017'),
('Mylapore', '6000014'),
('Gopalapuram', '6000087')
I Wrote a SQL Procedure as Below
DROP PROCEDURE IF EXISTS mp_test;
CREATE PROCEDURE mp_test(IN pArea VARCHAR(255))
BEGIN
SET #Query = 'SELECT PinCode FROM Areas';
IF pArea != ''
THEN
SET #City = CONCAT(' WHERE AreaName = ', pArea);
END IF;
SET #Query = CONCAT(#Query, #City);
PREPARE stmt FROM #Query;
EXECUTE stmt;
END
When I Call the Procedure
CALL mp_test('Teynampet');
When i Execute i am Not getting the Desired result i.e is 600018
How can i build query dynamically in SP
Thanks for the Help

You're concatenating the pArea parameter into the SQL unquoted. That is, the content of #Query that you prepare for execution is:
SELECT PinCode FROM Areas WHERE AreaName = Teynampet
Since Teynampet is unquoted, it is parsed as a(n unknown) SQL identifier rather than a string. You should either:
quote it in your SQL:
SET #City = CONCAT(' WHERE AreaName = ', QUOTE(pArea));
pass it to the prepared statement as a parameter:
SET #City = CONCAT(' WHERE AreaName = ?');
SET #param = pArea;
and then:
EXECUTE stmt USING #param;
However, why use prepared statements here? Your procedure can be rewritten as a simple SELECT (which raises the question of whether you need to use a stored procedure at all):
CREATE PROCEDURE mp_test(IN pArea VARCHAR(255))
SELECT PinCode FROM Areas WHERE pArea IN (AreaName, '');
(Note that I'd recommend you use NULL instead of the empty string '', in which case the above test would be pArea IS NULL OR pArea = AreaName).

Related

MySQL prepared statements with parameters not returning data

I have been trying to make parameterized prepared statements work. The first function only presents the header row with the column names and does not show any daya. The second
function provides all the data requested. The difference is that the first one uses parameters and the second only uses concatenated strings. The select statements in the first
function are used for debugging purposes, there are no NULL strings in any of the variables.
I would like to get the parameterized version working properly, I would appreciate any help.
I have already checked out these stackoverflow answers, Multiple Parameters, mysql Prepare Statement, Internals of prepared statement, unable to create prepared statements (might be the answer to my problem).
-- -----------------------------------------------------
-- procedure getAllBookDataWhere2
-- -----------------------------------------------------
USE `booklibinventory`;
DROP procedure IF EXISTS `booklibinventory`.`getAllBookDataWhere2`;
DELIMITER $$
USE `booklibinventory`$$
CREATE PROCEDURE `getAllBookDataWhere2`
(
IN whereStr VARCHAR(256)
)
BEGIN
DECLARE finalQuery VARCHAR(4096);
DECLARE selectedFields, leftJoinTables, joinOnFields VARCHAR(1024);
DECLARE whereClause, orderByClause VARCHAR(256);
SET #selectedFields = allBooksSelectFields();
SET #jointTables4Query = allBooksDataTables();
-- orderBy may become a parameter in the future.
SET #orderByClause = ' a.LastName, a.FirstName, s.SeriesName, v.VolumeNumber, t.TitleStr';
SET #whereclause = whereStr;
-- #selectedFields and #jointTables4Query are concatenated because they don't change,
-- #whereClause and #orderByClause can change and therefore are parameters.
SELECT #orderByClause;
SELECT #whereClause;
SET #finalQuery = CONCAT('SELECT ', #selectedFields);
SET #finalQuery = CONCAT(#finalQuery, ' FROM bookinfo AS BKI ');
SET #finalQuery = CONCAT(#finalQuery, #jointTables4Query);
SET #finalQuery = CONCAT(#finalQuery, ' WHERE ? ORDER BY ? ;');
SELECT #finalQuery;
PREPARE stmt FROM #finalQuery;
EXECUTE stmt USING #whereClause, #orderByClause;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
-- -----------------------------------------------------
-- procedure getAllBookDataWhere
-- -----------------------------------------------------
USE `booklibinventory`;
DROP procedure IF EXISTS `booklibinventory`.`getAllBookDataWhere`;
DELIMITER $$
USE `booklibinventory`$$
CREATE PROCEDURE `getAllBookDataWhere`
(
IN whereStr VARCHAR(256)
)
BEGIN
DECLARE finalQuery VARCHAR(4096);
DECLARE selectedFields, leftJoinTables, joinOnFields VARCHAR(1024);
DECLARE whereClause, orderByClause VARCHAR(256);
SET #selectedFields = allBooksSelectFields();
SET #jointTables4Query = allBooksDataTables();
-- orderBy may become a parameter in the future.
SET #orderByClause = ' ORDER BY a.LastName, a.FirstName, s.SeriesName, v.VolumeNumber, t.TitleStr;';
SET #whereclause = CONCAT(' WHERE ', whereStr);
-- #selectedFields and #jointTables4Query are concatenated because they don't change,
-- #whereClause and #orderByClause can change and therefore are parameters.
SET #finalQuery = CONCAT('SELECT ', #selectedFields);
SET #finalQuery = CONCAT(#finalQuery, ' FROM bookinfo AS BKI ');
SET #finalQuery = CONCAT(#finalQuery, #jointTables4Query);
SET #finalQuery = CONCAT(#finalQuery, #whereClause);
SET #finalQuery = CONCAT(#finalQuery, #orderByClause);
PREPARE stmt FROM #finalQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
Parameters are for values, not whole clauses. Your WHERE and ORDER BY clauses are effectively WHERE 'somestring' and ORDER BY 'somestring' (note the quotes).
Also, if I remember correctly, EXECUTEd statements do not add resultsets to a procedure's returned results; typically, the execute ends up needing to be an insert select into a temporary table that the procedure can select from directly before exiting.
Edit: Since you're already concat-ing the query together, you could just replace your ?-placeholders, ... WHERE ', #whereClause, ' ORDER BY ', #orderByClause, ';');
Parameters can't protect you from letting raw sql be "user" supplied.

Calling stored procedure with a string to use in query

I have a stored procedure where i need to pass a string to use in the query.
Stored procedure example:
BEGIN
SET #query = query;
SELECT * FROM test WHERE #query
END
How I would like to call it with a string:
CALL proceduretet('activity_id = 1 OR activity_id = 2')
The query can be different each time, sometimes there will be 1 activity_id and sometimes 4 or more.
I have tried to pass it as a varchar and text, but it won't work.
So is there a way to pass a string to stored procedures and use it in the query?
Regards, Andreas
The code would look like:
BEGIN
SET #query = query;
SET #sql = concat('SELECT * FROM TEST WHERE ', #query);
PREPARE stmt from #sql;
EXECUTE stmt;
END;

Using LIKE in a stored procedure and escaping injection at same time

So I have a stored procedure in MySQL
delimiter //
DROP PROCEDURE IF EXISTS mysearch;
CREATE PROCEDURE mysearch (IN term varchar(255), IN brands varchar(512), IN categories varchar(512), IN priceRange varchar(32))
BEGIN
SET #query = 'SELECT name, price, image FROM (... join some tables here ... ) WHERE (... prod.category = some number ...)';
IF (term IS NOT NULL) THEN
SET term = CONCAT('\'%',term,'%\'');
SET #query = CONCAT(#query, ' AND (prod.name LIKE ', QUOTE(term), ' OR prod.number LIKE ', QUOTE(term), ')');
END IF;
PREPARE stmt1 FROM #query;
EXECUTE stmt1;
END //
delimiter ;
How can I use LIKE and still escape user input?
I would like to sanitize user input, but still allow search using LIKE.
Perhaps something like this
DROP PROCEDURE IF EXISTS mysearch;
CREATE PROCEDURE mysearch (IN term varchar(255), IN brands varchar(512), IN categories varchar(512), IN priceRange varchar(32))
BEGIN
DECLARE fullterm varchar(255);
SET fullterm = CONCAT('%',term,'%');
SELECT name, price, image FROM (... join some tables here ... ) WHERE (... prod.category = some number ...)
AND (term IS NULL OR (prod.name LIKE fullterm OR prod.number LIKE fullterm));
END
Demo at http://sqlfiddle.com/#!2/a5e50/9
You can do that by using PREPARE statement.
There is an example here.

Assigning a SQL result to variable from prepared statement in MySQL

I am creating a stored procedure in MySQL and need to assign the results of a SQL query to a variable. The problem is that in order to create the SELECT statement, I have to use the CONCAT() function because I am passing in parameters.
Well it appears you can't use variables within the CONCAT function. Any ideas on how I can achieve this? The procedure I am trying to write is below:
DELIMITER //
CREATE PROCEDURE `my_proc` (IN tbl VARCHAR(20), IN col VARCHAR(20), IN id INT)
BEGIN
DECLARE #myval VARCHAR(100);
SET #t1 =CONCAT('SELECT ',col,' FROM ',tbl,' INTO #myval WHERE id = ',id );
PREPARE stmt1 FROM #t1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END //
Executing this gives me a SQL syntax error.
The problem is the following line:
...
-- SET #t1 = CONCAT('SELECT ',col,' FROM ',tbl,' INTO #myval WHERE id = ',id );
SET #t1 = CONCAT('SELECT ', col, ' INTO #myval FROM ', tbl, ' WHERE id = ', id);
...
Check the documentation: 13.2.9.1. SELECT ... INTO Syntax.
Here is a SQL Fiddle with an example.
It is important to indicate the difference between 9.4. User-Defined Variables (#t1 and #myval) and 13.6.4.1. Local Variable Syntax DECLARE (as could be: myval and t1), are different variables, therefore, it is not necessary to declare:
-- DECLARE #myval VARCHAR (100);

Dynamic table names in stored procedure function

I've written a stored procedure function to get a name from a table. The trouble is that I want the table name to be passed in as a parameter (there are several different tables I need to use this function with):
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `getName`(tableName VARCHAR(50), myId INT(11)) RETURNS VARCHAR(50)
begin
DECLARE myName VARCHAR(50);
SELECT
'name' INTO myName
FROM
tableName
WHERE
id=myId;
RETURN myName;
end
This method has an error because it uses the variable name "tableName" instead of the actual value of the variable.
I can work around this problem in a procedure by using a CONCAT like this:
SET #GetName = CONCAT("
SELECT
'name'
FROM
",tableName,"
WHERE
id=",myId,";
");
PREPARE stmt FROM #GetName;
EXECUTE stmt;
...but, when I try to do this in a function I get a message saying:
Dynamic SQL is not allowed in stored function or trigger
I tried to use a procedure instead, but I couldn't get it to just return a value, like a function does.
So, can anyone see a way to get around this problem. It seems incredibly basic really.
If you want to buld a SQL statement using identifiers, then you need to use prepared statements; but prepared statements cannot be used in functions. So, you can create a stored procedure with OUT parameter -
CREATE PROCEDURE getName
(IN tableName VARCHAR(50), IN myId INT(11), OUT myName VARCHAR(50))
BEGIN
SET #GetName =
CONCAT('SELECT name INTO #var1 FROM ', tableName, ' WHERE id=', myId);
PREPARE stmt FROM #GetName;
EXECUTE stmt;
SET myName = #var1;
END
Using example -
SET #tableName = 'tbl';
SET #myId = 1005;
SET #name = NULL;
CALL getName(#tableName, #myId, #name);
SELECT #name;