如何比较postgres中每列的两个相同表数据?

时间:2016-12-02 09:44:13

标签: postgresql

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

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

4 个答案:

答案 0 :(得分:1)

示例数据:

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)

答案 1 :(得分:0)

要获得可以使用的所有不同行:

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 :(得分:0)

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

只需用正确的表替换public.mytable1和public.mytable2即可 更新“where table_schema ='public'和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,'')

答案 3 :(得分:0)

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

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

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