比较所有列的MariaDB / MySQL的EXCEPT替代方案

时间:2017-02-27 23:19:29

标签: mysql function stored-procedures mariadb except

我知道MariaDB和MySQL不支持EXCEPT。 我想找到这样的替代方案:

SELECT * FROM table
EXCEPT
SELECT * FROM backup_table

表和backup_table具有相同的架构。

我见过的所有帖子都建议我使用“WHERE列IN(...)”来比较单个列。 我的问题是我需要比较每个表的两个表之间的所有列。我希望将此作为过程或函数循环遍历所有表,寻找数据库中的任何更改。基本上,我想找出所有已更新或插入所有表中的记录。

3 个答案:

答案 0 :(得分:2)

如果我遇到这个任务,我会使用反连接模式。这是一个外部联接,用于返回当前表中的所有行,以及"匹配"备份表中的行。然后在WHERE子句中,我们排除所有具有完全匹配的行。返回不匹配的行。

  SELECT t.*
    FROM mytable t
    LEFT
    JOIN backup_mytable s
      ON s.id        <=> t.id
     AND s.col_two   <=> t.col_two
     AND s.col_three <=> t.col_three
     AND ... 
 WHERE s.id IS NULL

这假设列id保证为非NULL。 PRIMARY KEY列(或者是表的PRIMARY KEY的任何列,或任何具有NOT NULL约束的列都可以服务。)

此查询仅返回与备份表中的行不匹配的行。它没有表明它的行是否存在,或者列的值是否发生了变化。

要在原始表中获取与备份表中的行不匹配的行,只需交换表名。

对于将所有列定义为NOT NULL的表的特殊情况,我们可以在连接谓词上使用快捷方式。

    FROM mytable t
 NATURAL
    LEFT
    JOIN backup_mytable s
   WHERE s.id IS NULL

这等同于LEFT JOIN,其中所有列的USING子句在两个表中都被命名为相同。

    FROM mytable t
    LEFT
    JOIN backup_mytable s
   USING (id, col_two, col_three, ...)
  WHERE s.id IS NULL

这等同于在每列上指定相等比较(如果两个表具有相同的列)

    FROM mytable t
    LEFT
    JOIN backup_mytable s
      ON s.id        = t.id
     AND s.col_two   = t.col_two
     AND s.col_three = t.col_three

任何列中出现任何NULL值都会使用相等比较,并返回NULL。

这就是为什么第一个查询使用空安全比较<=>(太空飞船)运算符的原因。 NULL <=> NULL将返回TRUE,其中NULL = NULL将返回NULL。

对于第一个查询模式,我会使用SQL来帮助我生成所需的SQL,而不是单调乏味地输入每列的所有比较。

 SELECT CONCAT('   AND s.`',c.column_name,'` <=> t.`',c.column_name,'`') AS `-- stmt`
   FROM information_schema.columns c
  WHERE c.table_schema = 'mydatabase'
    AND c.table_name = 'mytable'
  ORDER BY c.ordinal_position

我将获取该查询返回的行,并将其粘贴到

SELECT t.*
  FROM ... t
  JOIN ... s
    ON 1=1
    -- paste here --
 WHERE s.id IS NULL
ORDER BY t.id

如果我需要仅在id列上匹配的查询,并且需要识别哪些列已更改,我将在SELECT列表中使用表达式。例如:

 SELECT s.`id`        <=> t.`id`         AS `match_id`
      , s.`col_one`   <=> t.`col_one`    AS `match_col_one`
      , s.`col_three` <=> t.`col_three`  AS `match_col_three`
  FROM mytable t
  JOIN backup_mytable s
    ON s.id = t.id
HAVING NOT match_col_one

这里引用HAVING子句中SELECT列表中的列别名,以排除具有相同值col_one的行;返回col_one不同的行。

同样,我会对info_schema.columns使用SQL来帮助加快查询编写过程。

答案 1 :(得分:1)

我对MySQL或MariaDB没有多少经验,但我发现这是对可能对你有用的另一个问题的答案。

SELECT  *
FROM    match m
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    email e
        WHERE   e.id = m.id
        )

来自以下帖子的Quassnoi: MySQL SELECT x FROM a WHERE NOT IN ( SELECT x FROM b ) - Unexpected result

答案 2 :(得分:0)

version 10.3.0开始,MariaDB添加了对缺少的集合操作的支持,包括但不限于EXCEPT

computed: {
  searchTrigger () {
    if (this.search.length >= 3) {
       return this.search
    }
  }
}