phpmyadmin 并集5个或更多具有相同结构和主键的表

tkclm6bt  于 2022-11-09  发布在  PHP
关注(0)|答案(1)|浏览(138)

SQL 5.7.37版本
我正在使用这段代码将两个sql表合并成第三个表。但是现在我需要做同样的事情,用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);

如何向此命令添加更多表?
下面是一组示例数据和所需的结果:

请注意,这些表中有 * 一些 * 行与其他表完全相同。我不确定这是否重要。

结构:ID(主键、自动递增)、标题(唯一、索引)、DESC、URL
表一:
| 识别码|职务名称|描述|网址|
| - -|- -|- -|- -|
| 一个|鲍勃|这是鲍勃|bob.com|
| 2个|汤姆|此统|tom.com|
| 三个|乍得Name|蒂西沙德|chad.com|
表二:
| 识别码|职务名称|描述|网址|
| - -|- -|- -|- -|
| 一个|克里斯|蒂西克里斯|chris.com|
| 2个|乍得Name|蒂西沙德|chad.com|
| 三个|面团|这是面团|doug.com|
表三:
| 识别码|职务名称|描述|网址|
| - -|- -|- -|- -|
| 一个|摩根|这个器官|morgan.com|
| 2个|热罗姆|这是一个基因组|jerome.com|
| 三个|麦克|这个麦克风|mike.com|
表四:
| 识别码|职务名称|描述|网址|
| - -|- -|- -|- -|
| 一个|克里斯|蒂西克里斯|chris.com|
| 2个|乍得Name|蒂西沙德|chad.com|
| 三个|路加|锡斯卢克|luke.com|
结果(我需要表5中的内容):
| 识别码|职务名称|描述|网址|
| - -|- -|- -|- -|
| 一个|鲍勃|这是鲍勃|bob.com|
| 2个|汤姆|此统|tom.com|
| 三个|乍得Name|蒂西沙德|chad.com|
| 四个|克里斯|蒂西克里斯|chris.com|
| 五个|面团|这是面团|doug.com|
| 六个|摩根|这个器官|morgan.com|
| 七个|热罗姆|这是一个基因组|jerome.com|
| 八个|麦克|这个麦克风|mike.com|
| 九个|路加|锡斯卢克|luke.com|
如何向我的union sql命令中添加更多的表?

ulydmbyx

ulydmbyx1#

一个想法是,只要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

检查演示here

编辑:如何为此任务从MySQL表中选择除一个字段之外的所有字段

这样做有two interesting ways

1)第一种方法将每个表复制到不同的临时表中,然后使用ALTER语句删除我们不感兴趣的列,因此在此代码的第一个版本中使用这些表。


# for each table

CREATE TEMPORARY TABLE temp_Table1 AS
SELECT * FROM Table1;

ALTER TABLE temp_Table1
DROP Id;

2)第二种方法使用预准备语句,它允许您将查询构建为字符串。这对本练习很有帮助,因为我们可能希望在查询中检索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;

请注意,这段代码完全复制了这篇文章的第一段代码,只是使用了一个ROW_NUMBER窗口函数,而不是一个更新自身的全局变量。
此解决方案做了一些假设,根据这些假设,应仔细快速修复:

  • 表正好是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>
  • 当前表名为Table1Table2Table3Table4,数据库名为test:当我们查找特定表的字段名时(按表名和数据库名过滤),这些引用应该被替换:
SELECT '
   (SELECT CONCAT ...
    FROM ...
    WHERE cols.TABLE_NAME = <table_name> AND cols.TABLE_SCHEMA = <db_name>),
'FROM <table_name>
  • 要删除的字段名为“Id”,它是所有表的第一列:如果名称不同,则需要在删除此列的过程中更改其名称。此外,如果这不是第一列,则需要在此处进行一些调整:

# 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`'

(添加反勾号以避免由于DESC而导致的异常)

注1:可以自动生成每个表的四个SELECT组(this page底部的一个简单示例),方法是在INFORMATION_SCHEMA.TABLES中包含的表名上循环一个变量。(INFORMATION_SCHEMA.COLUMNS cols)的数据。
注意2:无法在sql fiddles中查看此代码的效果,因为无法访问INFORMATION_SCHEMA db表。此代码已在MySQL 8.0数据库上进行了脱机测试。

第一种方法可能会占用大量内存,而第二种方法如果在修改数据库时小心处理,可能会更有效。
总的来说没有完美的解决方案,虽然有些可能会解决你的问题。
附言:任何建议的修改,以改善这篇文章是非常欢迎的。

相关问题