MySQL Selecting From a Table name matching string - mysql

I'm relatively new to SQL and I've been having trouble trying to figure out how to select rows from a table that matches a string.
The name of the table uses the current month and year.
It looks like this:
XXXX.xxx_YY_MM
where XXXX is the database, YY is year, and MM is month.
So normally the query would just look like this:
select * from XXXX.xxx_16_05;
However, I want it to be able to change depending on the date.
So I thought this would work:
select * from (select concat('XXXX.xxx_',date_format(now(), '%y_%m'))));
The concat bit gives me something that looks exactly like the name of the table. But it doesn't work and I'm not sure why. It says every table must have it's own alias. I'm not sure what to do about it.
Alternatively, I was thinking maybe something like this would be ok
select * from (select * from information_schema.tables where table_name like concat('%logsms_',date_format(now(), '%y_%m'),'%'));
But it doesn't work either. What should I do? There is only one table with a name that matches the string.

You can't use an expression for the table name in SQL. You need to use a stored procedure that creates dynamic SQL and executes it using PREPARE and EXECUTE.
SET #sql = CONCAT('SELECT * FROM XXXX.xxx_', DATE_FORMAT(NOW(), '%y_%m'));
PREPARE stmt FROM #sql;
EXECUTE stmt;
A database design that requires this seems like a poor decision. You should have a single table where the date is in a column, not separate tables for each month.
If you're running the query from a programming language, you can use its own date functions to constructure SQL.

Please find the following query to retrieve all table by matching string.
select table_schema as database_name,table_name from information_schema.tables
where table_name like '%your_table_name%' order by table_schema, table_name;

Related

How to return a column value as text from a subquery in MySql?

I'm pretty new to MySql and this might seem like a stupid question, but i can't seem to find the answer anywhere.
I have two tables that I'm working with.
The first table contains a lot of columns filled with Integer values.
such as: No_of_Landlines No_of_mobiles
The second table is a Rule Table which contains a rule name followed by the actual rule.
Eg:
ID RuleName Rule
1 Example No_of_Landlines > No_of_Mobiles
The query that i want to run is this:
SELECT *
FROM DemoTable
WHERE (SELECT Rule from RuleTable WHERE ID=1)
What i want it to do is this:
SELECT *
FROM DemoTable
WHERE No_of_Landlines > No_of_Mobiles
When i run the first query against my database, it returns empty because the value of the rule being fetched from the Rule Table is a string and not a column name that I want, unlike query two under it.
How do I make the values of the string being returned into column names and execute the entire query?
One of my friends who's good with MSSQL suggested this:
DECLARE #a varchar(4000)
SET #a=(SELECT Rule FROM RuleDB WHERE ID=1)
print #a
EXEC('SELECT * FROM DemoTable WHERE ' + #a)
I tried this in MSSQL and it does work the way I want it to.
Is there a way to achieve this in MySql?
You can use EXECUTE command, this is a link to the syntax! .
Here is an example script:
SELECT #Q:= CONCAT('SELECT * FROM DemoTable WHERE ', Rules.Rule) FROM Rules WHERE ID=3;
PREPARE stq FROM #Q;
EXECUTE stq;
DEALLOCATE PREPARE stq;
In this script you create que query you want to execute in the variable #Q concatenating part of the query with the result of the rule you are fetching from the Rules table.
Then you prepare the statment, execute and deallocate.
You can define variables in MySQL and use them the same way you used them in MSSQL.
The complete documentation can be found here:
http://dev.mysql.com/doc/refman/5.5/en/user-variables.html

Search all columns of a table using a single where condition with single keyword in mysql

I have a table which consists of 64 different fields. i am going to search with a single keyword in it, Results should match the keyword from any field. Give some suggestions.
SELECT * FROM `some_table`
WHERE
CONCAT_WS('|',`column1`,`column2`,`column3`,`column4`,`column64`) # single condition, many columns
LIKE '%VT%'
Voila.
The '|' separator, by the way, is to prevent you finding coincidental matches where, e.g., column1 ends in 'V' and column2 starts with 'T', which would give you a false positive in a search for "VT".
I'm not sure if the above method is faster than the OR method (I would guess they're the same speed) , but it definitely involves less typing if you're writing the query by hand.
you can use the where with multiple condition with OR
like
where
name = 'expected'
OR rate ='expected'
OR country ='expected'
I can't see a way around your query being simple but long:
SET #term = "Somesearch";
SELECT id, title FROM sometable WHERE
col1 LIKE '%#term%' OR
col2 LIKE '%#term%' OR
col3 LIKE '%#term%' ...;
Instead of using a MySQL variable, you can just use a language-specific variable but for the sake of examples, I thought I'd stick with MySQL itself.
The "..." is where you'd place the other 61 columns/fields.
Another possibility would be to use FOR XML to get all columns to print to a single field... like this:
SELECT c.*
FROM (
SELECT a.*
,( SELECT *
FROM table_to_search b
WHERE a.KeyField = b.KeyField
FOR XML RAW) AS `Full_Text_Record`
FROM table_to_search a) c
WHERE c.`Full_Text_Record` LIKE '%Search_string%'
Might take a while to run if it is a particularly large table, but it should brute force you to find out if that string exists in any given table.
If you can translate this SQL Server syntax to MySQL
WHERE
name = #keyword OR
country = #keyword OR
department = #keyword OR
#keyword IS NULL -- match all when search text is empty
Simplest solution would be to use multiple ORs.
select * from TAB where col1 like "%VAR%" OR col2 like "%VAR%" OR......col64 like "%VAR%";
You can use like or = as per the requirement, but it will require to change your query every time you add a new column.
As an alternative, you can take SQLDump for that table and then search that file.
With some Googling,
See if this project is useful - http://code.google.com/p/anywhereindb/. Searches all the fields and praised by many.
Try to use the information from information_schema table. Look for all the columns in the table. Now, try to form your query using this information.
You could write one query that will generate a query for every column in your table.
In the example below the schema ("owner") is 'DEV_USER'
The table with your 64 fields is called 'CUSTOMER_INFO'
The criteria in the search is any column with a value of 'VT' in it:
select 'SELECT ' || COLUMN_NAME || ' FROM CUSTOMER_INFO
WHERE ' || COLUMN_NAME || q'# LIKE '%VT%';#'
FROM ALL_TAB_COLS
WHERE OWNER = 'DEV_USER'
AND TABLE_NAME = 'CUSTOMER_INFO';
This one query will generate a query for each field for you.
The results of running the above would be;
SELECT ADDRESS_1 FROM CUSTOMER_INFO
WHERE ADDRESS_1 LIKE '%VT%';
SELECT ADDRESS_2 FROM CUSTOMER_INFO
WHERE ADDRESS_2 LIKE '%VT%';
SELECT CITY FROM CUSTOMER_ADDRESSES_QASB
WHERE CITY LIKE '%VT%';
SELECT STATE_PROVINCE FROM CUSTOMER_INFO
WHERE STATE_PROVINCE LIKE '%VT%';
SELECT ZIP_POSTAL_CODE FROM CUSTOMER_INFO
WHERE ZIP_POSTAL_CODE LIKE '%VT%';
WHERE LATITUDE LIKE '%VT%';
... and so on for each column in the table
Then you just paste those queries that were generated from your first query into another tab and run them.
Hope that helps. :-)
You can use dynamic SQL to generate and execute a query that searches all the columns.
DELIMITER $$
CREATE PROCEDURE searchAllCols(inDB VARCHAR(64), inTable VARCHAR(64), search VARCHAR(32))
BEGIN
SET #matches = (
SELECT GROUP_CONCAT(CONCAT('`', COLUMN_NAME, '` LIKE "%', search, '%"') SEPARATOR ' OR ')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = inTable and table_schema = inDB);
SET #query = CONCAT('SELECT * FROM `', inDB, '`.`', inTable, '` WHERE ', #matches);
PREPARE stmt FROM #query;
EXECUTE stmt;
END
$$
DELIMITER ;
CALL searchAllCols('table_to_search', 'searchString');

Query a database with results from multiple tables?

There are some similar questions around but they aren't quite what I'm looking for, so forgive me if you think this is answered elsewhere.
I am basically looking for an easy way to do things as I have over 4000 tables to get data from. This kind of follows on from my previous post: mysql search for segment of table name
The general situation is that I have a database filled with tables and I only want about a quarter of this which comes to around 4000 tables. I have a list of the individual table names thanks to my previous post, but I want the data that goes with them.
I know that for an individual one I can do SELECT table1.*, table2.*; or something similar but I don't want to go through all 4000 or so.
They all end with the same thing, e.g. staff_name, manager_name, customer_name so I can use
SHOW TABLES LIKE '%_name'
to see the table names that I want in the database. Someone suggested using dynamic mysql, but I don't even know where to start with that. Any suggestions?
Generic example (in PHP):
Constructing dynamic SQL or building your SQL queries with the aid of a programming language would look like this (in PHP for ex.):
$pdos = $pdo->query("SHOW TABLES LIKE '%_name'");
$tables = $pdos->fetchAll();
$query = 'SELECT * FROM '.implode(' UNION SELECT * FROM ');
$pdo->query($query);
The fetchAll method will return an array containing the names of each table selected.
The implode($glue, $array) function takes an array and concatenates every value in the array using the $glue parameter - usually you take an array of values and implode them using $glue = ',' to create a coma separated list of values.
In our case the implode has a partial query as $glue in order to create one big UNION JOIN query.
Once the final $query is build it should look something like:
SELECT * FROM table_1_name
UNION
SELECT * FROM table_2_name
UNION
SELECT * FROM table_3_name
....
....
UNION
SELECT * FROM table_4000_name
The result should contain all of the DISTINCT rows from all 4000 tables.
Specific example (in SQL-only format):
SELECT GROUP_CONCAT(
CONCAT('select * from ', table_name)
SEPARATOR ' union '
)
INTO #my_variable
FROM information_schema.tables
WHERE table_schema = 'dbname'
AND table_name LIKE '%_name';
PREPARE my_statement FROM #my_variable;
EXECUTE my_statement;
The first statement will get all of the table names from the information_schema database;
The CONCAT function prefixes every table name with a a 'SELECT * FROM ' string;
The GROUP_CONCAT does the job that implode would have done in PHP;
The INTO clause makes sure the values are saved inside a variable named my_variable;
The PREPARE statement takes a string value (such as the one you saved in my_variable) and checks if the value is an SQL query;
The EXECUTE statement takes a "prepared statement" and well... executes it.
#my_variable is a temporary variable but it can only be of a scalar type (varchar, int, date, datetime, binary, float, double etc.) it is not an array.
The GROUP_CONCAT function is an "aggregate function" which means it takes an aggregate value (similar concept to an array - in our case the result set of our query) and outputs a simple string result.
I would suggest generating the SQL statement.
Try doing:
select concat('select * from ', table_name) as query
from Information_Schema.tables
where table_schema = <dbname> and
table_name like <whatever>
You can then run this as a bunch of queries by copying into a query editor window.
If you want everything as one query, then do:
select concat('select * from ', table_name, ' union all ') as query
from Information_Schema.tables
where table_schema = <dbname> and
table_name like <whatever>
And remove the final "union all".
This has the table name matching a like. Leave out the table_name part of the WHERE to get all tables. Or, include specific tables using table_name in ().

Select specific columns, along with the rest

I have a table with a lot of columns. Some of these are DATETIME, which I turn into Unix timestamps with UNIX_TIMESTAMP(). So I don't have to type out all the other columns I want from the table, is there a way of doing something like:
SELECT UNIX_TIMESTAMP(t.start) AS start,
UNIX_TIMESTAMP(t.end) AS end,
t.theOtherColumns
FROM table t
Where t.theOtherColumns is the rest of the columns in the table. To explain further; I want to select all the columns from the table, perform operations on some of them, but not type out each column name into the query.
When I do, say,
SELECT UNIX_TIMESTAMP(t.start) AS start,
UNIX_TIMESTAMP(t.end) AS end,
t.theOtherColumns
FROM table t
It selects start and end twice. I only want to return the start and end columns from UNIX_TIMESTAMP(), and exclude those columns from the t.* set.
What you can do is use this answer to help build the results you want.
A possible solution would look like
SET #sql = CONCAT('SELECT UNIX_TIMESTAMP(t.start) AS start, UNIX_TIMESTAMP(t.end) as end,', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM
information_schema.columns WHERE table_schema = 'test' AND table_name =
't' AND column_name NOT IN ('start', 'end')),
' from test.t');
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
*Replace test with the name of the schema that contains your table t.
Try t.* it works under Oracle.
I don't believe there is a way to do this as you suggested, but you can do this
SELECT t.*, UNIX_TIMESTAMP(t.start) AS start, UNIX_TIMESTAMP(t.end) as end ...

MySQL concat() to create column names to be used in a query?

I would like to concatenate column names in a way that the first part of the column name is a string and the second part is a number which is the result of another query.
For example:
SELECT CONCAT('column', mytable.mycolumn) FROM table ...
Can this be done in some way. This way it doesn't give me errors but I don't get the expected result and it seems the concatenation doesn't work.
I previously said that this couldn't be done, but I was wrong. I ended up needing something like this myself so I looked around, and discovered that server-side prepared statements let you build and execute arbitrary SQL statements from strings.
Here is an example I just did to prove the concept:
set #query := (
select concat(
"select",
group_concat(concat("\n 1 as ", column_name) separator ','),
"\nfrom dual")
from information_schema.columns
where table_name = 'columns')
;
prepare s1 from #query
;
execute s1
;
deallocate prepare s1
;
If the number of columns is fixed, then a non-dynamic approach could be:
select
case mytable.mycolumn
when 1 then column1 -- or: when 'a' then columna
when 2 then column2
when ...
else ...
end as my_semi_dynamic_column
from ...
I don't believe you can do this with CONCAT() and CONCAT_WS(). I'd recommend using the langauge you are working with the create the field names. Doing it this way would be pretty scary, depending on where the data in the database came from.
I would suggest looking at information_schema. The following code is untested but should theoretically work. Obviously replace your table name with an appropriate table name or link to information_schema.tables and use the table_type in your where clause
select concat('column', column_name) from information_schema.columns where table_name ='your table name'