给定两个 schema 一样的表,如何判断它们的数据是否相同?
假定有两张表 t1
、t2
,它们的主键都是 col1
。下面的语句可以把它们之中有区别的行查询出来:
SELECT * FROM t1 FULL OUTER JOIN t2
ON COALESCE(t1.col1, 0)=COALESCE(t2.col1, 0)
AND COALESCE(t1.col2, 0)=COALESCE(t2.col2, 0)
AND COALESCE(t1.col3, 0)=COALESCE(t2.col3, 0)
--- ... 所有其他字段
WHERE
(
t1.col1 IS NULL --- 这表示仅出现在 t2 中的行
OR t2.col1 IS NULL --- 这表示仅出现在 t1 中的行
)
重点在于:
- FULL OUTER JOIN:见 SQL: Queries: Table Expressions: Join
- 要进行比较的字段都应该在 JOIN 条件中
- 对于可能为 NULL 的字段,应该使用
COALESCE()
函数;因为NULL = NULL
的取值为 false- 当然这可能导致 NULL 与默认值(如 0)被认为是相等的
如果你期望缩小对比的数据范围,比如:
t1.grass_date=date'2021-07-20' AND t2.grass_date=date'2021-07-20';
那你不能直接在 WHERE
语句中添加。因为如果 t1 中有某行在 t2 中不存在,那么 FULL OUTER JOIN
的结果是,t1 的全部列有值,但 t2 的全部列为 NULL。如果你在 WHERE
中写上 t2.grass_date=date'2021-07-20'
条件,那么这些列会被过滤掉,也就达不到想要的目的。正确的做法应该是使用 CTE(with
语句):
WITH nt1 AS (
SELECT * FROM t1 WHERE t1.grass_date=date'2021-07-20'
), nt2 AS (
SELECT * FROM t2 WHERE t2.grass_date=date'2021-07-20'
)
SELECT * FROM nt1 FULL OUTER JOIN nt2
ON COALESCE(nt1.col1, 0)=COALESCE(nt2.col1, 0)
AND COALESCE(nt1.col2, 0)=COALESCE(nt2.col2, 0)
AND COALESCE(nt1.col3, 0)=COALESCE(nt2.col3, 0)
--- ... 所有其他字段
WHERE
(
nt1.col1 IS NULL --- 这表示仅出现在 t2 中的行
OR nt2.col1 IS NULL --- 这表示仅出现在 t1 中的行
)