Mysql select where field in csv string - mysql

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)

Related

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.

getting table name from a table and using the table name to access data

I want to create a database where there is a list of table names stored in a table. Now with the help of this list I can access the other tables.
Ex :-
Table name :- table_list (2 column i.e. table_name,table_id)
table_list attributes
authentication 1
basic_info 2
contact 3
I can directly access these tables using select statement but I want to access them using the table_list table preferably using select statement.
I tried
select * from (select table_name as x from table_list where id=2) as y
But could not get the proper output.
It is called Prepared Statements and their only use is when you want to implement your mentioned need in one request. Otherwise you can easily retrieve table names in a programming language and create your next statement using the data in hand. Here's how Prepared Statements work:
SELECT table_name INTO #tbl FROM my_tables WHERE id = 1 LIMIT 1;
SET #sql := CONCAT('SELECT * FROM ', #tbl);
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
TRY THIS
select * from (SELECT TABLE_NAME FROM TABLE_LIST WHERE ID=2)as y
The table name (an "identifier") must be a static part of the SQL text issed to the database; the identifier can't be supplied "on the fly", either as a parameter or as a result from another SQL query.
To do what you want to do, you will need a two step approach. You can use one (or more) SQL statements to obtain the identifiers you need (table name, column names, etc.), and then use that to dynamically create a second SQL statement, as a string.
The identifiers (table names, column anmes) can not be provided as parameters or "bind variables", they must be a static part of the SQL text.
For example, to generate the statement:
SELECT CONCAT('SELECT * FROM `',table_name,'` ORDER BY 1') AS stmt
FROM table_list
WHERE id = 2
(The coding details are dependent on what language you are using.)
Since you are sure that the table name you want to access is x, just check whether such a table exists using a query and use x for future purpose.

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

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.

MYSQL - Stored Procedure Utilising Comma Separated String As Variable Input

Im hoping someone will be able to help. I have created my first stored procdure (nothing fancy) however im running into an issue.
I want to give it a string input such as 1,2,3,4,5 then it does a simple SELECT * FROM [TABLE] WHERE EAN IN (VAR);
So the stored proc looks like this:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE PROCEDURE `moments`.`new_procedure`(IN var1 VARCHAR(255))
BEGIN
SELECT * FROM moments.PRODUCT WHERE EAN IN (var1);
END
Im am trying to execute it like such:
Works
call moments.new_procedure('5045318357397')
Does Not Work
call moments.new_procedure('5045318357397,5045318357427');
This executes but doesnt not bring back any results. Is it classing the second statement as a string so its doing this:
select * from moments.PRODUCT WHERE EAN IN ('5045318357397,5045318357427')
and not this:
select * from moments.PRODUCT WHERE EAN IN ('5045318357397','5045318357427')
How do i have to format the input in the execute query to get it to take a comma separated string as an input?
You could use:
SELECT * FROM moments.PRODUCT
WHERE FIND_IN_SET(EAN, var1)
This should work assuming it is actually comma delimited. Any other delimiting will not work in this case.
Assuming the string you passed is validated somehow and doesn't contain malicious sql, you can use prepared statements :
PREPARE stmt1 FROM CONCAT('select * from moments.PRODUCT WHERE EAN IN (',var1,')');
EXECUTE stmt1;

selecting first column from all tables in a mysql database

i have a column named "name" which is present in all tables in mysql database.
I wanted to list all the names in all tables so i used the following query
select name from (SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE') as abc
But it did not work for me and instead it returned me the table_name column alone.
Then i used show tables and stored the output in another table called table_list then i executed the following query
select name from (select table_name from table_list) as abc
This also returned me the same result i.e. all table names.
Can i know what is that i am doing wrong and what is the right way to do it?
I am using MySQL 5.4 and i want to either write a subquery or a procedure or a function purely in mysql.
There is PREPARE and EXECUTE which can run a sql statement from inside a user variable, so could probably use something similar to (untested!)
SET #a = "";
SELECT #a := CONCAT('(select name from ',GROUP_CONCAT(table_name SEPARATOR ') UNION (select name from '),')') FROM information_schema.tables WHERE table_type='BASE TABLE' GROUP BY 1;
PREPARE stmt FROM #a;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
What you need is a way to have variables in SQL (so you can say select * from $name where $name in (select ...)). SQL doesn't allow that.
My suggestion is to split the process up:
First run this query:
select 'select distinct name from ' || table_name || ' union'
from select table_name from table_list
That'll give you the selects to run. Put them into a small script, remove the last "union" and run that script.
[EDIT] If MySQL supports an "eval" operator in stored procedures (i.e. where you can build SQL from parts and then run it), you could do this. I checked the docs and it doesn't look like there is an eval. You could also write an extension in C (see chapter 22) that either implements the lookup or an "eval" function.
But my guess is that your database won't change all the time. So the most simple solution would be to write a small SQL script that creates the code for a view (that is a string; it doesn't actually create the view ). Every time the DB changes, you simply run the script to recreate the view and afterwards, you can run the query against the view to get a list of all names.