简体   繁体   English

联合5个或更多具有相同结构和主键的表

[英]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 ID Title标题 DESC DESC URL URL
1 1 Bob鲍勃 thisisbob这是鲍勃 bob.com鲍勃.com
2 2 Tom汤姆 thisistom这个主义 tom.com汤姆.com
3 3 Chad乍得 thisischad西沙德 chad.com乍得.com

Table 2:表 2:

ID ID Title标题 DESC DESC URL URL
1 1 Chris克里斯 thisischris这就是克里斯 chris.com克里斯.com
2 2 Chad乍得 thisischad西沙德 chad.com乍得.com
3 3 Dough面团 thisisdough这是面团 doug.com道格.com

Table 3:表3:

ID ID Title标题 DESC DESC URL URL
1 1 Morgan摩根 thisismorgan这个主义器官 morgan.com摩根com
2 2 Jerome杰罗姆 thisisjerome这是杰罗姆 jerome.com杰罗姆.com
3 3 Mike麦克风 thisismike类似的 mike.com麦克.com

Table 4:表 4:

ID ID Title标题 DESC DESC URL URL
1 1 Chris克里斯 thisischris这就是克里斯 chris.com克里斯.com
2 2 Chad乍得 thisischad西沙德 chad.com乍得.com
3 3 Luke卢克 thisisluke这就是卢克 luke.com卢克.com

Result (what I need in Table 5):结果(我在表 5 中需要的):

ID ID Title标题 DESC DESC URL URL
1 1 Bob鲍勃 thisisbob这是鲍勃 bob.com鲍勃.com
2 2 Tom汤姆 thisistom这个主义 tom.com汤姆.com
3 3 Chad乍得 thisischad西沙德 chad.com乍得.com
4 4 Chris克里斯 thisischris这就是克里斯 chris.com克里斯.com
5 5 Dough面团 thisisdough这是面团 doug.com道格.com
6 6 Morgan摩根 thisismorgan这个主义器官 morgan.com摩根com
7 7 Jerome杰罗姆 thisisjerome这是杰罗姆 jerome.com杰罗姆.com
8 8 Mike麦克风 thisismike类似的 mike.com麦克.com
9 9 Luke卢克 thisisluke这就是卢克 luke.com卢克.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_ALLUNION快得多,并且您将以这种方式执行一次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

Check the demo here .此处查看演示。


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:这个解决方案做了一些假设,根据这些假设,它应该被仔细地快速修复:

  • the tables are exactly 4: in order to change this amount, it's necessary to replicate the following code in the right place for each new table:这些表正好是 4:为了更改这个数量,有必要在每个新表的正确位置复制以下代码:
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>
  • the current table names are 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):当前的表名是Table1Table2Table3Table4 ,数据库名是test :当我们寻找特定表的字段名时,应该替换这些引用(按表名和数据库名过滤):
SELECT '
   (SELECT CONCAT ...
    FROM ...
    WHERE cols.TABLE_NAME = <table_name> AND cols.TABLE_SCHEMA = <db_name>),
'FROM <table_name>
  • the field name to remove is 'Id' and it is found as first column of all the tables: if the name is different, it's necessary to change its name during the removal of this column.要删除的字段名称是“Id”,它是所有表的第一列:如果名称不同,则需要在删除此列期间更改其名称。 Moreover if this is not the first column, some tweaks are needed here:此外,如果这不是第一列,则需要在此处进行一些调整:
# 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM