Using "IN" Statement for Stored Procedure Parameter SQL [duplicate] - mysql

This question already has answers here:
Parameterize an SQL IN clause
(41 answers)
Closed 9 years ago.
I have a stored procedure with one input parameter called "#IDs". This gets populated from my application which will populate it in the following format: '2, 30, 105'. The number of values inside this parameter will differ of course (For example: sometimes #IDs will be '100, 2005, 2, 510') My stored procedure is very simple. I have a table called "Persons". I'm trying to write this query:
Select * From Persons Where P_Id in (#IDs)
P_ID is the primary key in my table. The error I get is 'Conversion failed when converting the varchar value '2, 3, 4' to data type int.' Any suggestions will be greatly appreciated. Thanks.

One way is use dynamic SQL. That is generate the SQL as a string and then execute it.
An easier way (perhaps) is to use like:
where concat(', ', #IDS, ', ') like concat('%, ', id, ', %')
Note that this puts the separator at the beginning and end of the expressions, so "10" won't match "11010".

you might need to do a prepared statement. The idea is to build the select sentence and then execute it. Here's an example on how to do it...
USE mydb;
DROP PROCEDURE IF EXISTS execSql;
DELIMITER //
CREATE PROCEDURE execSql (
IN sqlq VARCHAR(5000)
) COMMENT 'Executes the statement'
BEGIN
SET #sqlv=concat(concat('select abc from yourtable where abc in (',sqll),')');
PREPARE stmt FROM #sqlv;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
Just change the query for the one you want to execute.

1) Show your code.
2) You've probably tried to pass in all the values as one parameter. That doesn't work. You have to list them as separate parameters and then bind them as separate parameters.
Yes, this makes it hard to use stored procedures when the number of in parameters may change.

Related

Mysql Stored Procedure: match the column rule to retrieve value

I have a stored procedure which function to retrieve the ColumnProperty based on the input parameter matching the ColumnRule.
For example,
I will execute the below to get the ColumnProperty as string(short). But the problem is when using WHERE to filter ColumnRule, the retrieved value is string and get unknown type at the end.
CALL `testing-spGetColumnType`('varchar(11)', #outputProperty);
select #outputProperty;
DELIMITER $$
CREATE PROCEDURE `testing-spGetColumnType`(IN pColumnType varchar(50),OUT pColumnProperty varchar(50))
BEGIN
SELECT ColumnProperty FROM model_column_type where pColumnType like replace(ColumnRule, 'variable', pColumnType) into pColumnProperty;
SELECT IFNULL(pColumnProperty,'unknown type') into pColumnProperty;
END$$
DELIMITER ;
The sample table:
when the condition in the WHERE clause is evaluated against the stringShort row, given 'varchar(11)' as the argument, it's equivalent to
WHERE 'varchar(11)'
LIKE '%varchar% and SUBSTRING_INDEX(SUBSTRING_INDEX(varchar(11),''('',-1),'')'',1) < 50'
and the result of the LIKE comparison will be FALSE.
The value of ColumnRule from that row
%varchar% and SUBSTRING_INDEX(SUBSTRING_INDEX(variable,'(',-1),')',1) < 50
is a value. It doesn't matter that it looks like SQL text. In the context of the SELECT statement, it is just a string of characters. It's a string value. It is not references to identifiers, or SQL functions, or boolean operators.
We would get the same result if the ColumnRule value was
%varchar% one two buckle my shoe
To get a string value to be seen as SQL text, we can use dynamically prepared SQL.
In the context of MySQL PROCEDURE, we can dynamically create SQL text and store it as a string, and then execute the string, something like this:
SET #foo = ' foo, bar' ;
SET #sql = CONCAT('SELECT ',#foo,' FROM mytab',' ORDER BY ',#foo);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
A word of caution: if we dynamically create SQL text, and incorporate potentially unsafe values, we can open a gaping SQL Injection vulnerability, ala Little Bobby Tables https://xkcd.com/327/
MySQL Reference https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-prepared-statements.html

Unknown Column in field list MySql stored procedure

i just create an stored procedure Scorer where parameter are like this
this the definition of Stored procedure
BEGIN
set #inser = CONCAT('INSERT INTO activity8',' (ActivityType,ActivityChapter,ActivitySubject,ActivityClass,Student) VALUES (',Type,',',Chapter,',',Subject,',',Class,',',Student,')');
prepare stmt from #inser;
execute stmt ;
End
this is the table structure of activity8 table
now when i call CALL Scorer('d',2,5,7,38)
why do it gives error #1054 - Unknown column 'd' in 'field list'
Edit
it works well when i do CALL Scorer('"d"',2,5,7,38) or CALL Scorer("'d'",2,5,7,38) can any body explain why ?
If your data is of varchar type and you are using CONCAT to build your query then it is not gonna work with single quotes as you are seeing already when you do
set #inser = CONCAT('INSERT INTO activity8',' (ActivityType,ActivityChapter,ActivitySubject,ActivityClass,Student) VALUES (',Type,',',Chapter,',',Subject,',',Class,',',Student,')');
when you do CALL Scorer('d',2,5,7,38);
it means your query is
#inser = INSERT INTO activity8 (ActivityType,ActivityChapter,ActivitySubject,ActivityClass,Student) VALUES
(d,2,5,7,38)
this is what your query is here your varchar type value d is without quotes
so one quote is consumed by the CONCAT itself
when you will prepare statement
prepare stmt from #inser;
execute stmt ;
your varchar value 'd' would be of without quotes
so you have to put your varchar paramter in like this "'d'" or '"d"'
one quote for concat and another one for the query itself
Try using double quotes on d.
CALL Scorer("d",2,5,7,38)
I think that should help you.
Probably because of that "Char" under Options for the "Type" parameter. What does that mean?

mysql stored procedure - order by column index

I'm wrining a stored procedure in mysql and I want to use a parameter for the column index in the order-by-clause. I've tried the following:
CREATE PROCEDURE `testProc` (
IN $sortColNum INT
)
BEGIN
SELECT id, title, date, sticky, published, created, updated, content
FROM news
ORDER BY $sortColNum DESC;
END
The stored procedure doesn't throw an error, but the result is unsorted. When i use the column index as a parameter in a prepared statement, it works fine. Why doesn't it work in a stored procedure?
This won't work. Your $sortColNum is treated as a constant rather than a column reference.
You have two choices. One is to use a prepare statement. The other is to explicitly list the columns in a case statement:
order by (case $sortColNum
when 1 then id
when 2 then title
when 3 then date
when 4 then sticky
. . .
end)
This method has the downside that all values are converted to the same data type (presumably strings). You might want to do explicit conversion yourself, in the event that the conversion affects the sort order.
Try this one:
CREATE PROCEDURE `testProc`(IN sortColNum INT)
BEGIN
SET #query = CONCAT ('SELECT id, title, date, sticky, published, created, updated, content
FROM news ORDER BY (',sortColNum,') DESC');
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END

Use of FInd_IN_SET vs IN clause MYSQL stored procedure

I have a stored procedure that is similar to below
SELECT *
FROM Table1
WHERE Tag IN (ids)
here Tag is an Integer column.
I tired to pass in comma separated values as string into the stored procedure but it does not work. Then I used stored procedure like below
SELECT *
FROM Table1
WHERE FIND_IN_SET(Tag, ids)
This works very well, the only problem is my table is very big - millions of rows and using FIND_IN_SET takes too long compared to IN when running a direct SQL statement.
What would be the best performance optimized option to use?
Is there a split function that can convert the ids into integer and parse it ready for IN clause? I think that would be the best option. Any suggestions or ideas?
You can prepare a statement and then execute it:
set #sql = concat('select * from table1 where tag in (', ids, ')');
PREPARE q FROM #sql;
execute q;
This constructs the string for each execution, so you can use in. The resulting execute should be able to use an index on tag, which should speed things up considerably.

Mysql select where field in csv string

I want to select from a table where a field is in a given csv string passed to a stored proc.
What is the fastest way to do this? Should I insert the values into a temporary table and join to that? Or is there a way to do it with one statement?
Thanks
Did some searching around and found a great answer.:)
Use MySql's string function FIND_IN_SET.
Example use:
SET #csvStr = "val1,val2,val3";
SELECT Col1
FROM Table1
WHERE FIND_IN_SET(Col2, #csvStr) > 0;
I edited the current answer with the "New Answer" and "Old Answer" pointing out that the new answer opens up your system to a SQL Injection vulnerability.
NEW ANSWER -
Well you have to do something like this as given below.
I am assuming your csv string would be as given in variable #str below. Else you need to make sure that your string (or arraystring) should have this format with single quotes for every element -
set #str = "'some1','some2','some3'";
set #qry1 = CONCAT('select * from testing where col1 in (',#str,')');
prepare stmt1 from #qry1;
execute stmt1;
deallocate prepare stmt1;
OLD ANSWER -
I assume that you will pass the csv file path to stored proc and read the lines in csv in that stored proc. So basically you can store all those csv field values in a temp table and write query using IN -
select * from sourceTable
where fieldValue in (select csvFieldValue from #temptable)