代码之家  ›  专栏  ›  技术社区  ›  shsteimer

查询具有相同规范的两个表的差异

sql
  •  1
  • shsteimer  · 技术社区  · 16 年前

    我最近不得不解决这个问题,发现我需要这个信息在过去很多次,所以我想我会张贴它。假设下表def,您将如何编写查询来查找两者之间的所有差异?

    表定义:

    CREATE TABLE feed_tbl
    (
    code varchar(15),
    name varchar(40),
    status char(1),
    update char(1)
    CONSTRAINT feed_tbl_PK PRIMARY KEY (code)
    
    CREATE TABLE data_tbl
    (
    code varchar(15),
    name varchar(40),
    status char(1),
    update char(1)
    CONSTRAINT data_tbl_PK PRIMARY KEY (code)
    

    这是我的解决方案,作为一个使用三个联合查询的视图。这个 diff_type 指定记录需要更新的方式:从 _data(2) ,更新于 _data(1) ,或添加到 _data(0)

    CREATE VIEW delta_vw AS (
    SELECT     feed_tbl.code, feed_tbl.name, feed_tbl.status, feed_tbl.update, 0 as diff_type
    FROM         feed_tbl LEFT OUTER JOIN
                          data_tbl ON feed_tbl.code = data_tbl.code
    WHERE     (data_tbl.code IS NULL)
    
    UNION
    
    SELECT     feed_tbl.code, feed_tbl.name, feed_tbl.status, feed_tbl.update, 1 as diff_type
    FROM         data_tbl  RIGHT OUTER JOIN
                          feed_tbl ON data_tbl.code = feed_tbl.code
    where (feed_tbl.name <> data_tbl.name) OR
    (data_tbl.status <> feed_tbl.status) OR
    (data_tbl.update <> feed_tbl.update) 
    
    
    UNION
    
    SELECT     data_tbl.code, data_tbl.name, data_tbl.status, data_tbl.update, 2 as diff_type
    FROM         feed_tbl LEFT OUTER JOIN
                          data_tbl ON data_tbl.code = feed_tbl.code
    WHERE     (feed_tbl.code IS NULL)
    
    )
    
    3 回复  |  直到 11 年前
        1
  •  2
  •   JosephStyons    16 年前

    UNION将删除重复项,因此只需将两个项合并在一起,然后搜索具有多个条目的任何内容。给定“code”作为主键,您可以说:

    编辑0:修改为包含PK字段本身的差异

    编辑1:如果你在现实生活中使用它,一定要列出实际的列名。不要使用点星,因为联合操作要求结果集具有完全匹配的列。如果从其中一个表中添加/删除列,则此示例将中断。

    select dt.*
    from
      data_tbl dt
     ,( 
      select code
      from
        (        
        select * from feed_tbl
        union
        select * from data_tbl        
        )
      group by code
      having count(*) > 1    
      ) diffs  --"diffs" will return all differences *except* those in the primary key itself 
    where diffs.code = dt.code
    union  --plus the ones that are only in feed, but not in data
    select * from feed_tbl ft where not exists(select code from data_tbl dt where dt.code = ft.code)
    union  --plus the ones that are only in data, but not in feed
    select * from data_tbl dt where not exists(select code from feed_tbl ft where ft.code = dt.code)
    
        2
  •  0
  •   Linus Caldwell Emperor 2052    11 年前

    我会在第二种情况下使用一个小的变化 union :

    where (ISNULL(feed_tbl.name, 'NONAME') <> ISNULL(data_tbl.name, 'NONAME')) OR
    (ISNULL(data_tbl.status, 'NOSTATUS') <> ISNULL(feed_tbl.status, 'NOSTATUS')) OR
    (ISNULL(data_tbl.update, '12/31/2039') <> ISNULL(feed_tbl.update, '12/31/2039')) 
    

    因为我不明白的原因, NULL 不等于 无效的 (至少在SQL Server中)。

        3
  •  0
  •   Community TheSoundDefense    7 年前

    你也可以用 FULL OUTER JOIN 以及 CASE ... END 关于 diff_type 列与前面提到的 where 从句 querying 2 tables with the same spec for the differences

    这可能会得到相同的结果,但在一个查询中。