2

我有两个表,一个源和一个目的地。如果源列中的任何相应列不同,我想标记要更新的目标表。列可以为空。

目前这似乎很笨拙:

UPDATE destination d
JOIN source s
   ON d.id = s.id
SET d.updateFlag = 1
WHERE (    (d.col1 IS NULL AND s.col1 IS NOT NULL) 
        OR (d.col1 IS NOT NULL AND s.col1 IS NULL)
        OR (d.col1 <> s.col1)
      )
      OR
      (    (d.col2 IS NULL AND s.col2 IS NOT NULL) 
        OR (d.col2 IS NOT NULL AND s.col2 IS NULL)
        OR (d.col2 <> s.col2)
      )
      ...etc...
      OR
      (    (d.colN IS NULL AND s.colN IS NOT NULL) 
        OR (d.colN IS NOT NULL AND s.colN IS NULL)
        OR (d.colN <> s.colN)
      )

理想情况下,我可以做类似的事情:

UPDATE destination d
JOIN source s
   ON d.id = s.id
SET d.updateFlag = 1
WHERE HASH(d.col1,d.col2,...etc...,d.colN) <> HASH(s.col1,s.col2,...etc...,s.colN)

一些额外的信息。这些列都是不同的数据类型(一些整数、一些位、一些字符串),我们使用的是 MySQL 5.1 的风格。

4

2 回答 2

2

您可以使用NULL 安全的等于运算符来简化语句:

UPDATE destination d
JOIN source s
   ON d.id = s.id
SET d.updateFlag = 1
WHERE !(d.col1 <=> s.col1)
   OR !(d.col2 <=> s.col2)
...etc

作为替代方案,您可以使用 UNION 来查找重复行:

  SELECT tbl, id, col1, col2, col3
    FROM (
  SELECT 't1' AS tbl, id, col1, col2, col3
    FROM t1
   UNION ALL
  SELECT 't2' AS tbl, id, col1, col2, col3
    FROM t2
       ) tmp
GROUP BY id, col1, col2, col3 HAVING COUNT(*) = 1;

然后,您可以在更新查询中使用结果:

UPDATE destination d
   SET d.updateFlag = 1
 WHERE EXISTS (
    SELECT NULL FROM (
        SELECT id, col1, col2, col3 FROM t1
        UNION All
        SELECT id, col1, col2, col3 FROM t2
     ) tmp
     WHERE d.id = tmp.id
  GROUP BY id, col1, col2, col3
    HAVING COUNT(*) = 1
)
于 2011-07-26T20:34:16.727 回答
1

您可能想查看mk-table-checksum,它是Maatkit中的工具之一。这就是您所描述的,计算整行的校验和并将其与另一个数据库中的相应行进行比较。

许多人使用此工具来验证从属服务器是否是其主服务器的真实副本,但您可以比较任何两个具有相似元数据的数据库。

于 2011-07-26T21:25:08.620 回答