mySQL query across multiple schemas - mysql

I have a multi-schema structure (same table across all schemas).
Here is how I can fetch all the schemas:
select table_schema from information_schema.tables where table_name = 'messages' and TABLE_TYPE = 'BASE TABLE'
This query is for a join between 'messages' table across two tables-
select *, '1' as customer from customer_1.messages union select *, '2' as customer from customer_2.messages
How do I use the perform the above query for all the schemas from the first query? Need not be a join. Could be anything that helps me return the results across all schemas.
Note: There could be 5000-10000 schemas

DELIMITER ##;
CREATE PROCEDURE join_all_data()
BEGIN
SET #counter := 0;
SELECT GROUP_CONCAT('select *, ',
#counter := #counter + 1,
' as customer from ',
table_schema,
'.messages'
SEPARATOR ' UNION ALL ')
FROM information_schema.tables
WHERE table_name = 'messages'
AND table_type = 'BASE TABLE'
INTO #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
##;
DELIMITER ;
CALL join_all_data;

Related

Is it possible to UNION ALL a prepared statement and a select statement?

I am trying to write up something that can be run once and exported with all the data from a prepared statement and a select statement. Is it possible to union them?
example dynamic pivot table
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'format(sum(case when field_key = ''',
field_key,
''' then field_value end), 0) ',
field_key
)
) INTO #sql
FROM
Meeting;
SET #sql = CONCAT('SELECT Meeting_id, ', #sql, '
FROM Meeting
GROUP BY Meeting_id'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
example select statement
set #startdate = '2020-11-10'
set #enddate = '2020-12-30'
select column1,
column2,
column3,
if(col.id = id,1,0) column4,
if(col.id = id,0,1) column5
from Meeting
group by col.id
order by column2;
If its not possible to UNION ALL them then what would be your suggestions?
Unions have to have the same number of columns (and their names are taken from the first query in the union), and here the pivot query has a dynamic number. You would need to adjust the columns of your second select to match and add it to your #sql as a union.
Often with unions you add a type field that is hardcoded and different for each of the unioned queries, and have each query return null for columns that aren't relevant to that query.

Subquery in FROM clause using information_schema.tables

I'am trying to get all tables from a database where table name contains 'logs' and get the sum last value in each table of a column named flag.
Query I tried:
Select SUM(flag) FROM (SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'db_test' AND table_name like '%logs') as c ORDER BY id DESC Limit 1;
But I'am having an issue with the subquery, I think the whole query is wrong.
I have broken this down into baby steps - nothing to stop you adjusting to taste.
drop table if exists onelog,twolog;
create table onelog (id int,flag int);
create table twolog (id int,flag int);
insert into onelog values (1,10),(2,1);
insert into twolog values (1,20),(2,1);
set #sql =
(
select group_concat(
concat('select id,flag from '
,tname, ' where id = (select max(id) from ', tname, ') union all'
)
)
from
(
select table_name tname from information_schema.tables where table_name like '%log' and table_schema = 'sandbox'
) s
)
;
set #sql = substring(#sql,1, length(#sql) - 10);
set #sql = replace(#sql,'union all,','union all ');
set #sql = concat('select sum(flag) from (', #sql , ' ) s');
#select #sql;
prepare sqlstmt from #sql;
execute sqlstmt;
deallocate prepare sqlstmt;
+-----------+
| sum(flag) |
+-----------+
| 2 |
+-----------+
1 row in set (0.001 sec)

how to select only non empty columns of a table from database

I have a table with 46 columns in my database, In these 46 columns 25 or 26 are mostly empty.
when I select all columns by some condition I want only those column will select which have some data in it
You can try this query to show you the not null columns' names:
SET group_concat_max_len = 4294967295;
SELECT GROUP_CONCAT(CONCAT(
' SELECT ',QUOTE(COLUMN_NAME),
' FROM table_name',
' WHERE `',REPLACE(COLUMN_NAME, '`', '``'),'` IS NOT NULL',
' HAVING COUNT(*)'
) SEPARATOR ' UNION ALL ')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'table_name';
PREPARE stmt FROM #sql;
EXECUTE stmt;
SQL Fiddle
And then just excute these columns manualy:
SELECT column_name3, column_name8 FROM Table_Name;
SQL Fiddle

Select table from database where value is X

So far I've found out that this gives me a list of all the tables which has the column name "store_id" - but I only want it to select the columns if "store_id" = 4, how could I do this?
Right now I use this to find the tables which has the "store_id" column.
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ('store_id')
AND TABLE_SCHEMA='db1';
You can it with dynamic SQL like this
SET #sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SELECT ''', TABLE_NAME,
''' table_name FROM ', TABLE_NAME,
' WHERE store_id = 4')
SEPARATOR ' UNION ALL ')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'store_id'
AND TABLE_SCHEMA = SCHEMA();
SET #sql = CONCAT(#sql, ' ORDER BY table_name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Sample output:
| TABLE_NAME |
-------------|
| table1 |
Here is SQLFiddle demo
Now you can simplify things on calling end by wrapping it up into a stored procedure
DELIMITER $$
CREATE PROCEDURE list_tables(IN _column_name VARCHAR(64), IN _column_value VARCHAR(256))
BEGIN
SET #sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SELECT ''', TABLE_NAME, ''' table_name
FROM ', TABLE_NAME,
' WHERE ', _column_name, ' = ''', _column_value, '''')
SEPARATOR ' UNION ALL ')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = _column_name
AND TABLE_SCHEMA = SCHEMA();
SET #sql = CONCAT(#sql, ' ORDER BY table_name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
And use it like this
CALL list_tables('store_id', '4');
Here is SQLFiddle demo
Use IF clause in MySQL.
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
IF(store_id = 4)
COLUMN_NAME = store_id
END IF;
OR
You can use case statement.
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE CASE WHEN store_id = 4
THEN COLUMN_NAME = store_id

resultset of particular query

I have this query. When I execute I got Query statement but I want result set of this query.
My query is:
SELECT CONCAT('select * from ', table_name, ' union all ') AS CUSTOMQUERY
FROM information_schema.tables
WHERE table_name LIKE '%custom%'
I get this result
select * from custom_70006 union all
select * from custom_704306 union all
select * from custom_700436 union all
select * from custom_7000643 union all
select * from custom_7000634 union all
select * from custom_700046 union all
select * from custom_700063 union all
select * from custom_700062 union all
But I want result set of this particular column with corresponding data and last union all should remove.
Please help me with relevant query.
I think this is what you are looking for:
SET GLOBAL group_concat_max_len = 4294967295;
SELECT #query1 := GROUP_CONCAT(CONCAT('SELECT * FROM ', table_name) SEPARATOR
' UNION ALL ') AS CUSTOMQUERY
FROM INFORMATION_SCHEMA.tables
WHERE TABLE_SCHEMA = SCHEMA()
AND table_name LIKE '%custom%';
PREPARE stmt FROM #query1; EXECUTE stmt; DEALLOCATE PREPARE stmt;
Example: SQLFiddle
or modify your query as:
SELECT #query1 := CONCAT('select * from ', table_name, ' union all ') AS
CUSTOMQUERY
FROM information_schema.tables
WHERE table_name LIKE '%custom%'
to remove last 'union all' string from your query:
SET #query1 = TRIM(TRAILING 'union all' FROM TRIM(#query1));
PS: Default value of group_concat_max_len is only 1024. So you need to set it to higher value otherwise the output of your query will get stripped and you may get syntax error.