【问题标题】:sql join: Detect changessql join:检测更改
【发布时间】:2019-07-17 21:26:01
【问题描述】:

定期,我想比较一个全局 sql 表(称为“resource”)和一个本地备份表(称为“region_db”),以查看字段是否已更改。我以这种方式监控的字段称为“状态”,主键称为“id”。目前我正在做

SELECT id, state FROM resource

然后手动循环遍历结果行。对于每个 (id, state) 元组,我都会这样做

SELECT state FROM region_db WHERE id = id

并检查来自本地 region_db 的状态是否与来自全局资源 db 的状态相匹配。我可以通过这种方式检测两种情况:1) 将新 id 添加到资源时,以及 2) 现有行的状态发生变化时。

但是,我错过了从资源表中删除行的情况。

我正在考虑使用 JOIN,但不确定如何有效区分这三种情况(修改现有、添加新和从资源表中删除行),同时最大限度地减少 JOIN/DB 操作的数量。

【问题讨论】:

  • @GordonLinoff 完成

标签: sql cockroachdb


【解决方案1】:

你可以使用full join:

select coalesce(r.id, reg.id) as id,
       (case when r.id is null then 'DELETED'
             when reg.id is null then 'CREATED'
             else 'UPDATED'
        end)
from resource r full join
     region_db reg
     on r.id = reg.id
where r.id is null or reg.id is null or r.state <> reg.state;  -- something changed

【讨论】:

  • 这有点复杂......他可以不使用UNION ALL 并检测存在于一个与另一个中的所有行吗?
  • @Zak 。 . .这对我来说似乎比 union all 更简单。
  • 这很漂亮。很好地使用了 case 语句、合并和外连接。
  • stackoverflow.com/questions/57915714/… @GordonLinoff 你能看一下吗?
【解决方案2】:
WITH joined AS (
  SELECT
    region.state as 'region_state',
    resource.state as 'global_state'
  FROM
    resource
  INNER JOIN
    region_db
  ON
    resource.id = region_db.id
) SELECT * FROM joined WHERE region_state <> 'global_state';

;

此查询将为您提供一个表,该表反映了现有行的状态何时发生变化。如果您在with 查询中执行left join 而不是inner join,您将获得可能已添加但尚未备份到region_db 的记录。同样,使用right join,您可能会获得已删除但尚未传播的记录。

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    您可以使用 UNION ALL 来告诉您表中的差异——基本上是检查 count(*) = 1 的位置,表示行不匹配的位置(因为 GROUP BY

    SELECT id,state
    FROM (
        SELECT id, state FROM resource
        UNION ALL
        SELECT id,state FROM region_db
        ) tbl
    GROUP BY id, state 
    HAVING count(*) = 1 
    ORDER BY id;
    

    【讨论】:

      猜你喜欢
      • 2014-10-29
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      • 2012-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      相关资源
      最近更新 更多