[英]Union 5 or more Tables with the same structure and primary key
SQL 5.7.37 SQL 5.7.37
I'm using this code to merge 2 sql tables into a third table.我正在使用此代码将 2 个 sql 表合并到第三个表中。 But now I need to do the same thing, with 5 or more tables.
但现在我需要做同样的事情,有 5 个或更多的表。
create table table3 as
select *
from table1
union all
select *
from table2
where not exists (select 1 from table1 where table1.title = table2.title);
How do I add more tables to this command?如何向此命令添加更多表?
Here's an example set of data and the desired result:这是一组示例数据和所需的结果:
Notice the tables have some rows that are exactly the same as other tables.请注意,这些表的某些行与其他表完全相同。 I'm not sure if that matters.
我不确定这是否重要。
Structure: ID (primary key, auto increment), Title (unique,index), DESC, URL结构:ID(主键,自增),Title(唯一,索引),DESC,URL
Table 1:表格1:
ID ![]() |
Title![]() |
DESC ![]() |
URL ![]() |
---|---|---|---|
1 ![]() |
Bob![]() |
thisisbob![]() |
bob.com![]() |
2 ![]() |
Tom![]() |
thisistom![]() |
tom.com![]() |
3 ![]() |
Chad![]() |
thisischad![]() |
chad.com![]() |
Table 2:表 2:
ID ![]() |
Title![]() |
DESC ![]() |
URL ![]() |
---|---|---|---|
1 ![]() |
Chris![]() |
thisischris![]() |
chris.com![]() |
2 ![]() |
Chad![]() |
thisischad![]() |
chad.com![]() |
3 ![]() |
Dough![]() |
thisisdough![]() |
doug.com![]() |
Table 3:表3:
ID ![]() |
Title![]() |
DESC ![]() |
URL ![]() |
---|---|---|---|
1 ![]() |
Morgan![]() |
thisismorgan![]() |
morgan.com![]() |
2 ![]() |
Jerome![]() |
thisisjerome![]() |
jerome.com![]() |
3 ![]() |
Mike![]() |
thisismike![]() |
mike.com![]() |
Table 4:表 4:
ID ![]() |
Title![]() |
DESC ![]() |
URL ![]() |
---|---|---|---|
1 ![]() |
Chris![]() |
thisischris![]() |
chris.com![]() |
2 ![]() |
Chad![]() |
thisischad![]() |
chad.com![]() |
3 ![]() |
Luke![]() |
thisisluke![]() |
luke.com![]() |
Result (what I need in Table 5):结果(我在表 5 中需要的):
ID ![]() |
Title![]() |
DESC ![]() |
URL ![]() |
---|---|---|---|
1 ![]() |
Bob![]() |
thisisbob![]() |
bob.com![]() |
2 ![]() |
Tom![]() |
thisistom![]() |
tom.com![]() |
3 ![]() |
Chad![]() |
thisischad![]() |
chad.com![]() |
4 ![]() |
Chris![]() |
thisischris![]() |
chris.com![]() |
5 ![]() |
Dough![]() |
thisisdough![]() |
doug.com![]() |
6 ![]() |
Morgan![]() |
thisismorgan![]() |
morgan.com![]() |
7 ![]() |
Jerome![]() |
thisisjerome![]() |
jerome.com![]() |
8 ![]() |
Mike![]() |
thisismike![]() |
mike.com![]() |
9 ![]() |
Luke![]() |
thisisluke![]() |
luke.com![]() |
How can I add more tables to my union sql command?如何向我的联合 sql 命令添加更多表?
An idea could be to postpone the generation of every unique value only after you've aggregated all your tables, as long as UNION_ALL
is way faster than UNION
, and you would do the DISTINCT
operation once instead of five times in this way.一个想法可能是仅在聚合所有表之后才推迟生成每个唯一值,只要
UNION_ALL
比UNION
快得多,并且您将以这种方式执行一次DISTINCT
操作而不是五次。
SET @cnt = 0;
SELECT (@cnt := @cnt + 1) AS rowNumber,
distinct_aggr_tables.*
FROM (SELECT DISTINCT *
FROM (SELECT `Title`, `DESC`, `url` FROM Table1
UNION ALL
SELECT `Title`, `DESC`, `url` FROM Table2
UNION ALL
SELECT `Title`, `DESC`, `url` FROM Table3
UNION ALL
SELECT `Title`, `DESC`, `url` FROM Table4) aggr_tables
) distinct_aggr_tables
EDIT: How to select all fields except one from a MySQL table for this task编辑:如何 select 除 MySQL 表中的一个之外的所有字段用于此任务
There are two interesting ways of doing this:有两种有趣的方法可以做到这一点:
1) The first approach copies each table into different temporary tables , then using the ALTER
statement to drop the column we're not interested in, hence using these tables with the first version of this code. 1)第一种方法将每个表复制到不同的临时表中,然后使用
ALTER
语句删除我们不感兴趣的列,因此将这些表与此代码的第一个版本一起使用。
# for each table
CREATE TEMPORARY TABLE temp_Table1 AS
SELECT * FROM Table1;
ALTER TABLE temp_Table1
DROP Id;
2) The second approach uses a prepared statement , which allows you to build the query as a string. 2)第二种方法使用准备好的语句,它允许您将查询构建为字符串。 This can help for this exercise because we may want to, retrieve all column names from
INFORMATION_SCHEMA.COLUMNS
table within a query, and then remove the field name we're not interested in, hence pass the list of column names to the original query.这有助于本练习,因为我们可能希望从查询中的
INFORMATION_SCHEMA.COLUMNS
表中检索所有列名,然后删除我们不感兴趣的字段名,从而将列名列表传递给原始查询。
SET @sql = CONCAT(
'CREATE OR REPLACE VIEW AllTables AS ',
'SELECT ROW_NUMBER() OVER(ORDER BY Title ASC) AS rowNumber,
distinct_aggr_tables.*
FROM (SELECT DISTINCT *
FROM (SELECT ',
(SELECT CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'),
'Id`,', ''),
'` ')
FROM INFORMATION_SCHEMA.COLUMNS cols
WHERE cols.TABLE_NAME = 'Table1' AND cols.TABLE_SCHEMA = 'test'),
'FROM Table1
UNION ALL
SELECT ',
(SELECT CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'),
'Id`,', ''),
'` ')
FROM INFORMATION_SCHEMA.COLUMNS cols
WHERE cols.TABLE_NAME = 'Table2' AND cols.TABLE_SCHEMA = 'test'),
'FROM Table2
UNION ALL
SELECT ',
(SELECT CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'),
'Id`,', ''),
'` ')
FROM INFORMATION_SCHEMA.COLUMNS cols
WHERE cols.TABLE_NAME = 'Table3' AND cols.TABLE_SCHEMA = 'test'),
'FROM Table3
UNION ALL
SELECT ',
(SELECT CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'),
'Id`,', ''),
'` ')
FROM INFORMATION_SCHEMA.COLUMNS cols
WHERE cols.TABLE_NAME = 'Table4' AND cols.TABLE_SCHEMA = 'test'),
'FROM Table4) aggr_tables) distinct_aggr_tables;'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
SELECT * FROM AllTables;
Note that this code reproduces exactly the first code of this post, except for the fact that uses a ROW_NUMBER
window function instead of a global variable that updates itself.请注意,此代码完全复制了本文的第一个代码,除了使用
ROW_NUMBER
window function 而不是更新自身的全局变量这一事实。
This solution makes some assumptions , according to which it should be carefully quick-fixed:这个解决方案做了一些假设,根据这些假设,它应该被仔细地快速修复:
SELECT ',
(SELECT CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'),
'Id`,', ''),
'` ')
FROM INFORMATION_SCHEMA.COLUMNS cols
WHERE cols.TABLE_NAME = <new_table_name> AND cols.TABLE_SCHEMA = 'test'),
FROM <new_table_name>
Table1
, Table2
, Table3
, Table4
and the database name is test
: these references should be replaced when we're looking for the field names of a specific table (filtering by table name and database name):Table1
、 Table2
、 Table3
、 Table4
,数据库名是test
:当我们寻找特定表的字段名时,应该替换这些引用(按表名和数据库名过滤):SELECT '
(SELECT CONCAT ...
FROM ...
WHERE cols.TABLE_NAME = <table_name> AND cols.TABLE_SCHEMA = <db_name>),
'FROM <table_name>
# COLUMN_NAME:
# ['Id', 'Title', 'DESC', 'url']
#
# GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'):
# 'Id`,`Title`,`DESC`,`url'
#
# REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'), 'Id`,', '')
# '`Title`,`DESC`,`url'
#
# CONCAT(REPLACE(GROUP_CONCAT(COLUMN_NAME SEPARATOR '`,`'), 'Id`,', ''), '` ')
# '`Title`,`DESC`,`url`'
(backticks are added to avoid exceptions due to DESC
) (添加反引号以避免由于
DESC
引起的异常)
Note1 : The generation of the four SELECT groups for each table may be automated (a simple example at the bottom of this page ) by cycling with a variable on the table names contained in INFORMATION_SCHEMA.TABLES
.注意 1:每个表的四个SELECT组的生成可以通过使用包含在
INFORMATION_SCHEMA.TABLES
中的表名上的变量来自动生成(本页底部的一个简单示例)。 Yet I wouldn't venture forth that path as it becomes difficult to deal with the string text to be evaluated with the prepared statement and the CONCAT of a calculated value from another table ( INFORMATION_SCHEMA.COLUMNS cols
).但是我不会冒险走这条路,因为很难处理要使用准备好的语句评估的字符串文本和来自另一个表(
INFORMATION_SCHEMA.COLUMNS cols
)的计算值的 CONCAT。
Note2 : Couldn't see the effects of this code within sql fiddles because wasn't able to access the INFORMATION_SCHEMA
db tables.注意 2:无法在sql小提琴中看到此代码的效果,因为无法访问
INFORMATION_SCHEMA
数据库表。 The code has been tested offline on a MySQL 8.0 database.该代码已在 MySQL 8.0 数据库上进行了离线测试。
The first approach can be quite memory expensive, while the second one may be more efficient if handled carefully in the fixes to tailor your db.第一种方法可能相当昂贵,而如果在修复中仔细处理以定制您的数据库,则第二种方法可能会更有效。
Overall no perfect solution, though some that may solve your problem.总体而言,没有完美的解决方案,尽管有些可能会解决您的问题。
ps: any suggested edits to improve this post are more than welcome. ps:任何改进这篇文章的建议编辑都非常受欢迎。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.