【问题标题】:How to compare two identicals tables data of each column in postgres?如何比较postgres中每列的两个相同的表数据?
【发布时间】:2023-03-08 14:00:01
【问题描述】:

我想比较两个表的所有列值。这两个表是相同的表意味着列号相同且主键相同。任何人都可以建议在 postgres 中比较这两个表的查询。 查询应该给出列名和两个表的两个不同值是什么。像这样

pkey | column_name | table1_value | table2_value
123  | bonus       |   1          |    0

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    要获取所有不同的行,您可以使用:

    select *
    from table_1 t1
      join table_2 t2 on t1.pkey = t2.pkey 
    where t1 is distinct from t2;
    

    这只会比较两个表中存在的行。如果您还想找到其中缺少的那些,请使用完整的外部联接:

    select coalesce(t1.pkey, t2.pkey) as pkey,
           case 
             when t1.pkey is null then 'Missing in table_1'
             when t2.pkey is null then 'Missing in table_2'
             else 'At least one column is different'
           end as status,
           *
    from table_1 t1
      full ojoin table_2 t2 on t1.pkey = t2.pkey 
    where (t1 is distinct from t2)
       or (t1.pkey is null)
       or (t2.pkey is null);
    

    如果您安装了hstore 扩展,您可以将差异视为键/值映射:

    select coalesce(t1.pkey, t2.pkey) as pkey,
           case 
             when t1.pkey is null then 'Missing in table_1'
             when t2.pkey is null then 'Missing in table_2'
             else 'At least one column is different'
           end as status,
           hstore(t1) - hstore(t2) as values_in_table_1, 
           hstore(t2) - hstore(t1) as values_in_table_2
    from table_1 t1
      full ojoin table_2 t2 on t1.pkey = t2.pkey 
    where (t1 is distinct from t2)
       or (t1.pkey is null)
       or (t2.pkey is null);
    

    使用此示例数据:

    create table table_1 (pkey integer primary key, col_1 text, col_2 int);
    insert into table_1 (pkey, col_1, col_2) 
    values (1, 'a', 1), (2, 'b', 2), (3, 'c', 3), (5, 'e', 42);
    
    create table table_2 (pkey integer primary key, col_1 text, col_2 int);
    insert into table_2 (pkey, col_1, col_2) 
    values (1,'a', 1), (2, 'x', 2), (3, 'c', 33), (4, 'd', 52);
    

    可能的结果是:

    pkey | status                           | values_in_table_1 | values_in_table_2
    -----+----------------------------------+-------------------+------------------
       2 | At least one column is different | "col_1"=>"b"      | "col_1"=>"x"     
       3 | At least one column is different | "col_2"=>"3"      | "col_2"=>"33"    
       4 | Missing in table_1               |                   |                  
       5 | Missing in table_2               |                   |                  
    

    【讨论】:

      【解决方案2】:

      我尝试了以上所有答案。谢谢大家的帮助。谷歌搜索后我发现了一个简单的查询。

      SELECT <common_column_list> from table1
      EXCEPT
      SELECT <common_column_list> from table2.
      

      如果 table1 的任何列值与 table2 的列值不同,则显示 table1 的所有行。

      【讨论】:

      • 恭喜谷歌搜索成功!然而,答案不满足问题的条件。
      【解决方案3】:

      示例数据:

      create table test1(pkey serial primary key, str text, val int);
      insert into test1 (str, val) values ('a', 1), ('b', 2), ('c', 3);
      
      create table test2(pkey serial primary key, str text, val int);
      insert into test2 (str, val) values ('a', 1), ('x', 2), ('c', 33);
      

      这个简单的查询提供了有关两个表的差异的完整信息(包括其中一个表中缺少的行):

      (select 1 t, * from test1
      except
      select 1 t, * from test2)
      union all
      (select 2 t, * from test2
      except
      select 2 t, * from test1)
      order by pkey, t;
      
       t | pkey | str | val 
      ---+------+-----+-----
       1 |    2 | b   |   2
       2 |    2 | x   |   2
       1 |    3 | c   |   3
       2 |    3 | c   |  33
      (4 rows)
      

      在 Postgres 9.5+ 中,您可以使用 jsonb functions 将结果转换为预期格式:

      select pkey, key as column, val[1] as value_1, val[2] as value_2
      from (
          select pkey, key, array_agg(value order by t) val
          from (
              select t, pkey, key, value
              from (
                  (select 1 t, * from test1
                  except
                  select 1 t, * from test2)
                  union all
                  (select 2 t, * from test2
                  except
                  select 2 t, * from test1)
              ) s,
              lateral jsonb_each_text(to_jsonb(s))
              group by 1, 2, 3, 4
          ) s
          group by 1, 2
      ) s
      where key <> 't' and val[1] <> val[2]
      order by pkey;
      
       pkey | column | value_1 | value_2 
      ------+--------+---------+---------
          2 | str    | b       | x
          3 | val    | 3       | 33
      (2 rows)
      

      【讨论】:

        【解决方案4】:

        不是很好,但很有趣,而且很有效 :o)

        只需将 public.mytable1 和 public.mytable2 替换为正确的表和 更新“ where table_schema='public' and table_name='mytable1'”

        select * from (
            select pkey,column_name,t1.col_value table1_value,t2.col_value table2_value from (
        select pkey,generate_subscripts(t,1) ordinal_position,unnest(t) col_value  from (
         select pkey,
        (
           replace(regexp_replace(   -- null fields 
             '{'||substring(a::character varying,'^.(.*).$') ||'}' -- {} instead of  ()
        ,'([\{,])([,\}])','\1null\2','g'),',,',',null,')
        )::TEXT[] t 
        from public.mytable1 a 
        ) a) t1 
        left join (
            select pkey,generate_subscripts(t,1) ordinal_position,unnest(t) col_value  from (
          select pkey,
        (
           replace(regexp_replace(   -- null fields 
             '{'||substring(a::character varying,'^.(.*).$') ||'}' -- {} instead of  ()
        ,'([\{,])([,\}])','\1null\2','g'),',,',',null,')
        )::TEXT[] t 
           from public.mytable2 a 
         ) a) t2  using (pkey,ordinal_position)
        
         join (select * from information_schema.columns where table_schema='public' and table_name='mytable1') c using (ordinal_position)
         ) final where COALESCE(table1_value,'')!=COALESCE(table2_value,'')
        

        【讨论】:

          猜你喜欢
          • 2011-06-16
          • 1970-01-01
          • 1970-01-01
          • 2020-11-28
          • 1970-01-01
          • 1970-01-01
          • 2015-07-04
          • 2017-10-29
          • 1970-01-01
          相关资源
          最近更新 更多