MariaDB/MySQL 比较所有列的 EXCEPT 的替代方法
Alternative for EXCEPT for MariaDB/MySQL comparing all columns
我知道 MariaDB 和 MySQL 不支持 EXCEPT。
我想找到这样的替代方法:
SELECT * FROM table
EXCEPT
SELECT * FROM backup_table
其中 table 和 backup_table 具有相同的架构。
我看到的所有帖子都建议我使用 "WHERE column IN (...)" 比较单个列。
我的问题是我需要比较每个 table 的两个 table 之间的所有列。我希望将其编写为遍历所有 table 的过程或函数,以查找数据库中的任何更改。基本上,我想找出我所有 table 中已更新或插入的所有记录。
我对 MySQL 或 MariaDB 没有太多经验,但我发现这是对另一个可能对您有用的问题的回答。
SELECT *
FROM match m
WHERE NOT EXISTS
(
SELECT 1
FROM email e
WHERE e.id = m.id
)
Quassnoi 的功劳来自以下 post:
MySQL SELECT x FROM a WHERE NOT IN ( SELECT x FROM b ) - Unexpected result
如果我面临那个任务,我会使用反加入模式。这是一个外部联接,return 来自当前 table 的所有行,以及来自备份 table 的 "matching" 行。然后在 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 列(或 table 的 PRIMARY KEY 的一部分的任何列,或任何具有 NOT NULL 约束的列。)
此查询仅 return 与备份 table 中的行不匹配的行。它不表示它的行是否不存在,或者列的值是否被更改。
要获取原始 table 中与备份 table 中的行不匹配的行,只需交换 table 名称即可。
对于所有列都定义为 NOT NULL 的 table 的特殊情况,我们可以在连接谓词上采取快捷方式。
FROM mytable t
NATURAL
LEFT
JOIN backup_mytable s
WHERE s.id IS NULL
这相当于在两个 table 中具有相同名称的所有列的 USING 子句的 LEFT JOIN。
FROM mytable t
LEFT
JOIN backup_mytable s
USING (id, col_two, col_three, ...)
WHERE s.id IS NULL
这相当于在每一列上指定相等比较(如果两个 table 具有相同的列)
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 值都会影响相等比较,return NULL。
这就是第一个查询使用空值安全比较 <=>
(宇宙飞船)运算符的原因。 NULL <=> NULL
将 return 为真,其中 NULL = NULL
将 return 为空。
对于第一个查询模式,与其单调乏味地输入每一列的所有这些比较,我会使用 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
我会采用该查询 return 编辑的行,并将其粘贴到
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
的行; returning 行 col_one
不同。
同样,我会使用 SQL 而不是 information_schema.columns 来帮助加快查询编写过程。
从 version 10.3.0, MariaDB added support for missing set operations, including but not limited to EXCEPT 开始。
CREATE TABLE `table` ( `item` VARCHAR(1) NOT NULL );
CREATE TABLE `backup_table` ( `item` VARCHAR(1) NOT NULL );
INSERT INTO `table` VALUES ( 'a' ), ( 'b' ), ( 'c' );
INSERT INTO `backup_table` VALUES ( 'a' ), ( 'b' ), ( 'd' );
SELECT * FROM `table`
EXCEPT
SELECT * FROM `backup_table`;
+------+
| item |
+------+
| c |
+------+
我知道 MariaDB 和 MySQL 不支持 EXCEPT。 我想找到这样的替代方法:
SELECT * FROM table
EXCEPT
SELECT * FROM backup_table
其中 table 和 backup_table 具有相同的架构。
我看到的所有帖子都建议我使用 "WHERE column IN (...)" 比较单个列。 我的问题是我需要比较每个 table 的两个 table 之间的所有列。我希望将其编写为遍历所有 table 的过程或函数,以查找数据库中的任何更改。基本上,我想找出我所有 table 中已更新或插入的所有记录。
我对 MySQL 或 MariaDB 没有太多经验,但我发现这是对另一个可能对您有用的问题的回答。
SELECT *
FROM match m
WHERE NOT EXISTS
(
SELECT 1
FROM email e
WHERE e.id = m.id
)
Quassnoi 的功劳来自以下 post: MySQL SELECT x FROM a WHERE NOT IN ( SELECT x FROM b ) - Unexpected result
如果我面临那个任务,我会使用反加入模式。这是一个外部联接,return 来自当前 table 的所有行,以及来自备份 table 的 "matching" 行。然后在 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 列(或 table 的 PRIMARY KEY 的一部分的任何列,或任何具有 NOT NULL 约束的列。)
此查询仅 return 与备份 table 中的行不匹配的行。它不表示它的行是否不存在,或者列的值是否被更改。
要获取原始 table 中与备份 table 中的行不匹配的行,只需交换 table 名称即可。
对于所有列都定义为 NOT NULL 的 table 的特殊情况,我们可以在连接谓词上采取快捷方式。
FROM mytable t
NATURAL
LEFT
JOIN backup_mytable s
WHERE s.id IS NULL
这相当于在两个 table 中具有相同名称的所有列的 USING 子句的 LEFT JOIN。
FROM mytable t
LEFT
JOIN backup_mytable s
USING (id, col_two, col_three, ...)
WHERE s.id IS NULL
这相当于在每一列上指定相等比较(如果两个 table 具有相同的列)
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 值都会影响相等比较,return NULL。
这就是第一个查询使用空值安全比较 <=>
(宇宙飞船)运算符的原因。 NULL <=> NULL
将 return 为真,其中 NULL = NULL
将 return 为空。
对于第一个查询模式,与其单调乏味地输入每一列的所有这些比较,我会使用 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
我会采用该查询 return 编辑的行,并将其粘贴到
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
的行; returning 行 col_one
不同。
同样,我会使用 SQL 而不是 information_schema.columns 来帮助加快查询编写过程。
从 version 10.3.0, MariaDB added support for missing set operations, including but not limited to EXCEPT 开始。
CREATE TABLE `table` ( `item` VARCHAR(1) NOT NULL );
CREATE TABLE `backup_table` ( `item` VARCHAR(1) NOT NULL );
INSERT INTO `table` VALUES ( 'a' ), ( 'b' ), ( 'c' );
INSERT INTO `backup_table` VALUES ( 'a' ), ( 'b' ), ( 'd' );
SELECT * FROM `table`
EXCEPT
SELECT * FROM `backup_table`;
+------+
| item |
+------+
| c |
+------+