SQL - Get databases which contain a specific record - mysql

So originally I have this as a test run.
SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema LIKE '%or';
I have looked around and found queries to show all the databases that contain a specific table.
However is it possible to have a query to go a step further and do the following:
"Select all those databases that have a particular table in them and that, in that table, have a particular record in a particular column."?

You cannot do what you want with a SQL statement.
But, you can use SQL to generate the statement that you want. The basic statement is:
select "tablename"
from tablename
where columnname = value
limit 1
Note that value may need to have single quotes around it. You can generate this with:
select concat('select "', c.table_name, '" ',
'from ', c.schema_name, '.', c.table_name, ' ',
'where ', c.column_name, ' = ', VALUE, ' '
'limit 1'
)
from information_schema.columns c
where c.table_name = TABLENAME and c.column_name = COLUMN_NAME;
To put all the statements in one long SQL statement, use:
select group_concat(concat('select "', c.table_name, '" as table_name',
'from ', c.schema_name, '.', c.table_name, ' ',
'where ', c.column_name, ' = ', VALUE, ' '
'limit 1'
) SEPARATOR ' union all '
)
from information_schema.columns c
where c.table_name = TABLENAME and c.column_name = COLUMN_NAME;
I would then just copy the resulting SQL statement and run it. If you like, you can add a prepare statement and run it dynamically.

as an example,
I have a table named T1 with columns (C1,C2), and I am searching for the value 'Needle'.
What this store procedure does is search through table names that starts with T and columns that starts with C, then loop through them and finds the value 'Needle'. It then returns the table_Schema,table_name,column_name and how many times the value 'Needle' is found within that column_name,table_name,table_schema combination.
see this sqlFiddle
CREATE PROCEDURE findDatabase(IN in_value varchar(50))
BEGIN
DECLARE bDone INT;
DECLARE _TableSchema VARCHAR(50);
DECLARE _TableName VARCHAR(50);
DECLARE _ColumnName VARCHAR(50);
DECLARE curs CURSOR FOR SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME FROM information_schema.columns WHERE TABLE_NAME LIKE "T%" AND COLUMN_NAME LIKE "C%";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
DROP TEMPORARY TABLE IF EXISTS tblResults;
CREATE TEMPORARY TABLE IF NOT EXISTS tblResults (
id int auto_increment primary key,
tableSchema varchar(50),
tablename varchar(50),
columnname varchar(50),
timesFound int
);
OPEN curs;
SET bDone = 0;
REPEAT
FETCH curs INTO _TableSchema,_TableName,_ColumnName;
SET #found = 0;
SET #sql = CONCAT("SET #found = (SELECT COUNT(*) FROM ",_TableSchema,".",_TableName,
" WHERE ",_ColumnName,"='",in_value,"')");
PREPARE statement FROM #sql;
EXECUTE statement;
IF (#found > 0) THEN
INSERT INTO tblResults(tableSchema,tableName,columnName,TimesFound) VALUES (_TableSchema,_TableName,_ColumnName,#found);
END IF;
UNTIL bDone END REPEAT;
CLOSE curs;
SELECT DISTINCT TableSchema,TableName,ColumnName,TimesFound FROM tblResults;
DROP TABLE tblResults;
END//

Related

select from unknown number of tables with parameter

I want to select (union) rows from multiple tables using Parameter
I have table w with two columns:
The column table_name is referring to other tables in my DB, and condition is the 'where' that should be added to the query.
table_name | condition
---------------------
x | y=2
x | r=3
t | y=2
the query should be something like:
select * from x where y=2
union
select * from x where r=3
union
select * from t where y=2
of course that the number of unions is unknown.
Should it be stored procedure? cursor?
One way to get this done. Initial answer was SQL Server syntax. This edit has the MySQL syntax. Make sure your temp table cannot be accessed at the same time. E.g. In MySQL temp tables are unique to the connection. Also add your error checking. In MySQL set the appropriate varchar size for your needs. I used 1024 across the board just for testing purposes.
MySQL syntax
CREATE table test (
id int,
table_name varchar(1024),
where_c varchar(1024)
);
INSERT into test(id, table_name, where_c) values
(1,'x','y=2'),
(2,'x','r=3'),
(3,'t','y=2');
DROP PROCEDURE IF EXISTS generate_sql;
DELIMITER //
CREATE PROCEDURE generate_sql()
BEGIN
DECLARE v_table_name VARCHAR(1024);
DECLARE v_where_c VARCHAR(1024);
DECLARE table_id INT;
DECLARE counter INT;
DECLARE v_SQL varchar(1024);
CREATE TEMPORARY table test_copy
SELECT * FROM test;
SET v_SQL = '';
SET counter = (SELECT COUNT(1) FROM test_copy);
WHILE counter > 0 DO
SELECT id, table_name, where_c
INTO table_id, v_table_name, v_where_c
FROM test_copy LIMIT 1;
SET v_SQL = CONCAT(v_SQL, 'SELECT * FROM ', v_table_name, ' WHERE ', v_where_c);
DELETE FROM test_copy WHERE id=table_id;
SET counter = (SELECT COUNT(1) FROM test_copy);
IF counter > 0 THEN
SET v_SQL = CONCAT(v_SQL,' UNION ');
ELSE
SET v_SQL = v_SQL;
END IF;
END WHILE;
DROP table test_copy;
SELECT v_SQL;
END //
DELIMITER ;
call generate_sql()
SQL Server syntax
CREATE table test (
id int,
table_name varchar(MAX),
condition varchar(MAX)
);
INSERT into test(id, table_name, condition) values
(1,'x','y=2'),
(2,'x','r=3'),
(3,'t','y=2');
SELECT * INTO #temp FROM test;
DECLARE #SQL varchar(MAX);
SET #SQL='';
while exists (select * from #temp)
begin
DECLARE #table_name varchar(MAX);
DECLARE #condition varchar(MAX);
DECLARE #table_id int;
SELECT top 1 #table_id=id, #table_name=table_name, #condition=condition FROM #temp;
SET #SQL += 'SELECT * FROM ' + #table_name + ' WHERE ' + #condition;
delete #temp where id = #table_id;
if exists (select * from #temp) SET #SQL += ' UNION ';
end
SELECT #SQL;
drop table #temp;
Assuming that tables x and t have the same definition and that you want to ignore duplicate results by using UNION rather than UNION ALL, the following should work:
SET #sql = '';
SELECT GROUP_CONCAT(
CONCAT('SELECT * FROM `', `table_name`, '` WHERE ', `condition`)
SEPARATOR ' UNION ') INTO #sql
FROM w;
SET #sql = CONCAT('SELECT * FROM ( ', #sql, ' ) a;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
(I've edited your question slightly because you had two different definitions for table x)

MySQL Procedure to synchronize the schema of 2 tables

The goal is to add the missing columns when comparing the schemas of two tables in MySQL 5.5 (engine MyISAM). The argument p_table1 is the model table name from which p_table2 will be compared and "synchronized".
When it is called, nothing happens, no errors, no nothing. I've tried to log some variables but it hasn't worked either.
What could be wrong with the code?
CREATE PROCEDURE synchronize_tables(p_table1 VARCHAR(64), p_table2 VARCHAR(64), p_schema_name VARCHAR(64))
BEGIN
DECLARE v_done INT default false;
DECLARE v_actual_column_name VARCHAR(64);
DECLARE v_does_columns_exist INT default true;
DECLARE v_column_type LONGTEXT;
DECLARE v_column_default LONGTEXT;
DECLARE v_is_nullable VARCHAR(3);
DECLARE v_cur CURSOR FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table1
AND table_schema = p_schema_name;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
OPEN v_cur;
read_loop: LOOP
FETCH v_cur INTO v_actual_column_name;
IF v_done THEN
LEAVE read_loop;
END IF;
SELECT count(*) INTO v_does_columns_exist
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table2
AND table_schema = p_schema_name
AND column_name = v_actual_column_name;
IF NOT v_does_columns_exist THEN
SELECT column_type, COLUMN_DEFAULT, IS_NULLABLE
INTO v_column_type, v_column_default, v_is_nullable
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table1
AND table_schema = p_schema_name
AND column_name = v_actual_column_name;
SET #stmt_text = CONCAT('ALTER TABLE ', p_schema_name, '.', p_table2,
' ADD COLUMN ', v_actual_column_name, ' ', v_column_type, ' ', IF(upper(v_is_nullable) = 'NO', 'NOT NULL', ''),
' DEFAULT ', v_column_default);
prepare v_stmt FROM #stmt_text;
execute v_stmt;
deallocate prepare v_stmt;
END IF;
END LOOP;
CLOSE v_cur;
END;
END
I found a couple of problems.
First is that most of your cursor code is inside an EXIT HANDLER FOR SQLEXCEPTION. This block is run only if an error occurs. So normally this block will never be run.
Second, you CONCAT() columns to form your ALTER TABLE statement, but one or more of the columns can be NULL. When you CONCAT() any string with a null, the result of the whole concat operation is NULL. So you have to make sure NULLs are defaulted to something non-NULL.
In my test, the column default is frequently NULL. We'd want this to become the keyword "NULL" in the ALTER TABLE statement. Also if the default is not NULL, you probably want to quote it, because an ordinary default value may be a string or a date, and you aren't quoting it. The solution: QUOTE() is a builtin function that quotes strings properly, and it even turns a NULL into the keyword "NULL".
Here's what I got to work:
CREATE PROCEDURE synchronize_tables(p_table1 VARCHAR(64),
p_table2 VARCHAR(64), p_schema_name VARCHAR(64))
BEGIN
DECLARE v_done INT default false;
DECLARE v_actual_column_name VARCHAR(64);
DECLARE v_does_columns_exist INT default true;
DECLARE v_column_type LONGTEXT;
DECLARE v_column_default LONGTEXT;
DECLARE v_is_nullable VARCHAR(3);
DECLARE v_cur CURSOR FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table1
AND table_schema = p_schema_name;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE;
OPEN v_cur;
read_loop: LOOP
FETCH v_cur INTO v_actual_column_name;
IF v_done THEN
LEAVE read_loop;
END IF;
SELECT count(*) INTO v_does_columns_exist
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table2
AND table_schema = p_schema_name
AND column_name = v_actual_column_name;
IF NOT v_does_columns_exist THEN
SELECT column_type, COLUMN_DEFAULT, IS_NULLABLE
INTO v_column_type, v_column_default, v_is_nullable
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = p_table1
AND table_schema = p_schema_name
AND column_name = v_actual_column_name;
SET #stmt_text = CONCAT('ALTER TABLE ',
p_schema_name, '.', p_table2,
' ADD COLUMN ', v_actual_column_name, ' ',
v_column_type, ' ',
IF(upper(v_is_nullable) = 'NO', 'NOT NULL', ''),
' DEFAULT ', QUOTE(v_column_default));
PREPARE v_stmt FROM #stmt_text;
EXECUTE v_stmt;
DEALLOCATE prepare v_stmt;
END IF;
END LOOP;
CLOSE v_cur;
END
There are other problems with this approach:
Identifiers are not delimited.
It generates one ALTER TABLE for each missing column, even though one can add multiple columns in one ALTER.
It doesn't do the right thing when a column is NOT NULL but has no default.
However, I wouldn't do this with cursors anyway. There's an easier way:
CREATE PROCEDURE synchronize_tables(p_table1 VARCHAR(64),
p_table2 VARCHAR(64), p_schema_name VARCHAR(64))
BEGIN
SELECT CONCAT(
'ALTER TABLE `', C1.TABLE_SCHEMA, '`.`', p_table2, '` ',
GROUP_CONCAT(CONCAT(
'ADD COLUMN `', C1.COLUMN_NAME, '` ', C1.COLUMN_TYPE,
IF(C1.IS_NULLABLE='NO', ' NOT NULL ', ''),
IF(C1.COLUMN_DEFAULT IS NULL, '',
CONCAT(' DEFAULT ', QUOTE(C1.COLUMN_DEFAULT)))
) SEPARATOR ', '
)
) INTO #stmt_text
FROM INFORMATION_SCHEMA.COLUMNS AS C1
LEFT OUTER JOIN INFORMATION_SCHEMA.COLUMNS AS C2
ON C1.TABLE_SCHEMA=C2.TABLE_SCHEMA
AND C2.TABLE_NAME=p_table2
AND C1.COLUMN_NAME=C2.COLUMN_NAME
WHERE C1.TABLE_SCHEMA=p_schema_name AND C1.TABLE_NAME=p_table1
AND C2.TABLE_SCHEMA IS NULL;
PREPARE v_stmt FROM #stmt_text;
EXECUTE v_stmt;
DEALLOCATE prepare v_stmt;
END
This makes one ALTER TABLE to add all columns. It delimits identifiers. It handles NOT NULL better.
But even my solution still has problems:
Causes an error if you try to add a NOT NULL column with no DEFAULT to a populated table2.
Doesn't notice extra columns that exist in the second table but not the first table.
Doesn't synchronize constraints, indexes, triggers, procedures, or views.
It's a very complex task to sync database structure completely. I suggest that trying to use MySQL's stored procedure language for this is making a hard task even harder.
MySQL's implementation of stored procedures sucks.
Poor documentation.
No support for packages.
No standard procedures or rich function library.
No real debugger exists (some tools try, but they're faking it).
No support for persisting compiled procedures. Procedures are recompiled by every session that uses them.
I often recommend to developers who are accustomed to using procedures in Oracle or Microsoft SQL Server, to stay away from MySQL stored procedures.

Error Code: 1111. Invalid use of group function inside of a stored procedure to create triggers automatically

I'm trying to create a stored procedure that would create triggers automatically for all the tables that exist in my Database.
I came up with the following code but I got this error when I run it:
Error Code: 1111. Invalid use of group function
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
# DECLARE column_name VARCHAR(255);
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
# SET #s = CONCAT('SELECT ''', table_name, ''', COUNT(*) AS Count FROM ' , table_name);
SET #s = CONCAT('DROP TRIGGER IF EXISTS auditemployees_insert;
CREATE TRIGGER audit',
table_name,
'_insert AFTER INSERT ON ',
table_name,
'
FOR EACH ROW
BEGIN
INSERT INTO ',
table_name,
'_trigger (',
GROUP_CONCAT(CONCAT('`', column_name, '`')
SEPARATOR ','),
') SELECT ',
GROUP_CONCAT(CONCAT('`', column_name, '`')
SEPARATOR ','),
' FROM ',
table_name,
' WHERE id = NEW.id;
END$$');
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Any ideas how to correct my error?
Yo, please do try this one out, mate:
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
-- DECLARE column_name VARCHAR(255);
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
-- SET #s = CONCAT('SELECT ''', table_name, ''', COUNT(*) AS Count FROM ' , table_name);
SET #s = CONCAT(
'DELIMITER $$',
'DROP TRIGGER IF EXISTS auditemployees_insert; CREATE TRIGGER audit',
table_name,
'_insert AFTER INSERT ON ',
table_name,
'FOR EACH ROW BEGIN INSERT INTO ',
table_name,
'_trigger (',
"GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',')",
') SELECT ',
"GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',')",
' FROM ',
table_name,
"WHERE id = NEW.id;"
"END$$"
);
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Notes:
This type/style of implementation is not really recommended, especially if you will put this into a production level of environment
This will provide output/expected outcome but can sacrifice maintainability due to improper implementation
I like the idea of making a trigger through a stored procedure, but somehow I am against it
The only error I can see is the proper usage of ' and "
Proper indentation helps, trust me
And the commented line(s), you know what to do with those
Anyway, cheers
You're missing a query and then trying to fit it into the construction of the trigger code string. For each table, you need to
SELECT GROUP_CONCAT(CONCAT('`', column_name, '`') SEPARATOR ',') INTO #columnsList FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = [the current table name]
;
You could also just join to INFORMATION_SCHEMA.COLUMNS (on table_schema and table_name) in your cursor query, and have two fields; table_name and columns_list.
Edit: Also, I am not sure how much prepared statements accept multiple statements; so you may want to prepare and execute the preliminary DROP of each trigger separately from it's (re)creation.
Also:
I am not sure what purpose you had in mind for the COUNT query.
You may want to filter table names ending in _trigger from your cursor.
Edit: Something like this... (untested, so I might have typos or other similar oversights)
DELIMITER $$
DROP PROCEDURE IF EXISTS procCountAllTables $$
CREATE PROCEDURE procCountAllTables()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE trigger_name VARCHAR(255);
DECLARE target_tablename VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
DECLARE column_names VARCHAR(1024);
-- Be aware of GROUP_CONCAT's configured length limitation
DECLARE cur CURSOR FOR
SELECT t.table_name
, GROUP_CONCAT(CONCAT("`",c.column_name,"`")) AS column_names
FROM information_schema.tables AS t
INNER JOIN information_schema.columns AS c
USING (table_schema, table_name)
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE'
GROUP BY t.table_name
;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name, column_names;
IF end_of_tables = 1 THEN
LEAVE tables_loop;
END IF;
SET target_tablename := CONCAT(table_name, '_trigger');
SET trigger_name := CONCAT('audit', table_name, '_insert');
SET #s := CONCAT("DROP TRIGGER IF EXISTS `", trigger_name, "`;");
PREPARE stmt FROM #s;
EXECUTE stmt;
SET #s := CONCAT(
"CREATE TRIGGER `", trigger_name, "` "
"AFTER INSERT ON `", table_name, "` "
"FOR EACH ROW "
"INSERT INTO `", target_tablename, "` (", column_names, ") "
"SELECT ", column_names, " "
"FROM `", table_name, "` "
"WHERE id = NEW.id "
";"
;
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Note that I've removed the BEGIN and END from the trigger definition. Since the trigger itself executes only a single statement, I think they are not necessary; and in my limited experience with these specific kinds of tasks, a delimiter override (which was not actually done on the prepare statement) tends to confuse prepared statements.
Also, you can probably get away without even using a select in the trigger if the cursor is changed like so:
SELECT t.table_name
, GROUP_CONCAT(CONCAT("`", column_name, "`")) AS column_names
, GROUP_CONCAT(CONCAT("NEW.`", column_name, "`")) AS source_list
...
and the trigger insert changed like so:
...
"INSERT INTO `", target_tablename, "` (", column_names, ") "
"VALUES (", source_list, ") "
";"
of course, you'll need to fetch the source_list from the cursor into a source_list local variable.

How to get example values from every column in a schema

I'm reverse-engineering a MySQL database and I'd like to get a list of example values from every column in every table. I'd like to run a query like this:
select
table_name,
column_name,
group_concat(
(select distinct table_name.column_name limit 100)
separator ','
) as examples
from
information_schema.columns
where
table_schema = 'myschema'
;
I'd like the output to look something like this:
table1 column1 (123,124,234)
table1 column2 ('Joe','Sara','Bob')
MySQL won't accept table_name.column_name as valid syntax. What's the right way to write this query?
I think Sam, you are looking for something like that, or at least it would be a better approach:
select
table_name,
column_name,
group_concat((column_name) separator ',') as examples
from
information_schema.columns
where
table_schema = 'test'
GROUP BY table_name
;
Based on rene's suggestion, I wrote a stored procedure which outputs examples of values from each column in every table. It's ugly and slow, but it works. I'd welcome suggestions on how to improve this code.
DELIMITER //
CREATE PROCEDURE column_example_values(
IN db_name VARCHAR(64),
IN tbl VARCHAR(64),
IN col VARCHAR(64),
OUT result MEDIUMTEXT)
BEGIN
SET #s = CONCAT('SELECT GROUP_CONCAT(tbl1.',col,
' separator \',\') FROM (SELECT DISTINCT ',
col,' FROM ',db_name,'.',tbl,
' LIMIT 100) tbl1 INTO #result1');
PREPARE stmt FROM #s;
EXECUTE stmt;
SET result = IFNULL(#result1,'');
END;
//
DELIMITER ;
DELIMITER //
CREATE PROCEDURE all_columns_example_values(IN db_name VARCHAR(64))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tbl, col VARCHAR(64);
DECLARE cur1 CURSOR FOR
SELECT
table_name,
column_name
FROM
information_schema.columns
WHERE
table_schema = db_name
ORDER BY
table_name,
column_name;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
CREATE TEMPORARY TABLE results (
tbl VARCHAR(64), col VARCHAR(64), examples MEDIUMTEXT);
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tbl, col;
IF done THEN
LEAVE read_loop;
END IF;
CALL column_example_values(db_name,tbl,col,#result);
INSERT INTO results (tbl, col, examples) VALUES (tbl, col, #result);
END LOOP;
CLOSE cur1;
SELECT * FROM results;
DROP TABLE results;
END;
//
DELIMITER ;
It can be called with
CALL all_columns_example_values('mydb');

Procedure UNION on tables

How can I UNION all results from stmtQuery to ONE RESULTS example results from table basia and Comments_11 .... etc
DELIMITER $$
DROP PROCEDURE IF EXISTS SearchUserY $$
CREATE PROCEDURE `SearchUserY`(IN UserIdValue INT(11) )
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tableName VARCHAR(50);
DECLARE stmtFields TEXT ;
DECLARE columnName VARCHAR(50) default 'UserId';
DECLARE cursor1 CURSOR FOR
SELECT table_name
FROM information_schema.COLUMNS
WHERE table_schema = 'comments'
AND column_name LIKE '%UserId';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor1;
read_loop: LOOP
FETCH cursor1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
SET stmtFields = CONCAT('`',tableName,'`','.' , columnName ,'=', UserIdValue) ;
SET #stmtQuery=CONCAT(#sql,'SELECT Nick, Title, Content FROM ' ,'`',tableName,'`', ' WHERE ', stmtFields ) ;
select #stmtQuery;
END LOOP;
PREPARE stmt FROM #stmtQuery ;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
CLOSE cursor1;
END
results example (select #stmtQuery):
SELECT Nick, Title, Content FROM `basia` WHERE `basia`.UserId=0
SELECT Nick, Title, Content FROM `Comments_11` WHERE `Comments_11`.UserId=0
... etc
I want get a one results from all this query but know I got only One results
Generate query in a loop using CONCAT function, add 'UNION' or 'UNION ALL' clause between them, then execute result query with a prepared statements.
Solution without cursor:
SET #resultQuery = NULL;
SELECT
GROUP_CONCAT(
DISTINCT
CONCAT('SELECT Nick, Title, Content FROM ', table_name, ' WHERE UserId = ', UserIdValue)
SEPARATOR '\r\nUNION\r\n'
)
INTO
#resultQuery
FROM
information_schema.COLUMNS
WHERE
table_schema = 'comments' AND column_name LIKE '%UserId';
SELECT #resultQuery;
It will produce result like this:
SELECT Nick, Title, Content FROM table1 WHERE UserId = 10
UNION
SELECT Nick, Title, Content FROM table2 WHERE UserId = 10
UNION
SELECT Nick, Title, Content FROM table3 WHERE UserId = 10
UNION
SELECT Nick, Title, Content FROM table4 WHERE UserId = 10
...
Increase group_concat_max_len variable if needed. It is the maximum allowed result length for the GROUP_CONCAT() function, default value = 1024.