PostgreSQL 如何比较两个表的定义是否一致

一位网友提到的需求, 在PostgreSQL中如何比对两个表的定义差异.
如果只比对字段类型, 不比对约束, 触发器, 策略, 权限等其他属性的话, 只需要使用pg_attribute这个catalog即可.
例子 :
创建两个测试表,
postgres=# create table tbl1 (id int, info text, c1 numeric(10,3), c2 timestamp without time zone);
CREATE TABLE
postgres=# create table tbl2 (id int, info text, c0 int, c00 int, c1 numeric(10,3), c2 timestamp with time zone);
CREATE TABLE

postgres=# alter table tbl2 drop column c00;
ALTER TABLE

postgres=# alter table tbl2 add column c00 int;
ALTER TABLE
postgres=# alter table tbl2 add column c01 int;
ALTER TABLE

当前结构
postgres=# \d tbl1
               Table "public.tbl1"
 Column |            Type             | Modifiers
--------+-----------------------------+-----------
 id     | integer                     |
 info   | text                        |
 c1     | numeric(10,3)               |
 c2     | timestamp without time zone | 

postgres=# \d tbl2
              Table "public.tbl2"
 Column |           Type           | Modifiers
--------+--------------------------+-----------
 id     | integer                  |
 info   | text                     |
 c0     | integer                  |
 c1     | numeric(10,3)            |
 c2     | timestamp with time zone |
 c00    | integer                  |
 c01    | integer                  | 

使用这个catalog
postgres=# \d pg_attribute
    Table "pg_catalog.pg_attribute"
    Column     |   Type    | Modifiers
---------------+-----------+-----------
 attrelid      | oid       | not null
 attname       | name      | not null
 atttypid      | oid       | not null
 attstattarget | integer   | not null
 attlen        | smallint  | not null
 attnum        | smallint  | not null
 attndims      | integer   | not null
 attcacheoff   | integer   | not null
 atttypmod     | integer   | not null
 attbyval      | boolean   | not null
 attstorage    | "char"    | not null
 attalign      | "char"    | not null
 attnotnull    | boolean   | not null
 atthasdef     | boolean   | not null
 attisdropped  | boolean   | not null
 attislocal    | boolean   | not null
 attinhcount   | integer   | not null
 attcollation  | oid       | not null
 attacl        | aclitem[] |
 attoptions    | text[]    |
 attfdwoptions | text[]    |
Indexes:
    "pg_attribute_relid_attnam_index" UNIQUE, btree (attrelid, attname)
    "pg_attribute_relid_attnum_index" UNIQUE, btree (attrelid, attnum)

当前两个表在pg_attribute中的数据如下, 系统隐含列和已删除的列排除掉
postgres=# select attrelid,attname,atttypid,attlen,atttypmod from pg_attribute where attrelid='tbl2'::regclass and attnum>=1 and not attisdropped;
 attrelid | attname | atttypid | attlen | atttypmod
----------+---------+----------+--------+-----------
    24681 | id      |       23 |      4 |        -1
    24681 | info    |       25 |     -1 |        -1
    24681 | c0      |       23 |      4 |        -1
    24681 | c1      |     1700 |     -1 |    655367
    24681 | c2      |     1184 |      8 |        -1
    24681 | c00     |       23 |      4 |        -1
    24681 | c01     |       23 |      4 |        -1
(7 rows)

postgres=# select attrelid,attname,atttypid,attlen,atttypmod from pg_attribute where attrelid='tbl1'::regclass and attnum>=1 and not attisdropped;
 attrelid | attname | atttypid | attlen | atttypmod
----------+---------+----------+--------+-----------
    24675 | id      |       23 |      4 |        -1
    24675 | info    |       25 |     -1 |        -1
    24675 | c1      |     1700 |     -1 |    655367
    24675 | c2      |     1114 |      8 |        -1
(4 rows)

使用这个SQL就可以比对两个表不同的字段
with
t1 as (
select attrelid,attname,attlen,format_type(atttypid,atttypmod) as typ from pg_attribute where attrelid='tbl1'::regclass and attnum>=1 and not attisdropped
),
t2 as (
select attrelid,attname,attlen,format_type(atttypid,atttypmod) as typ from pg_attribute where attrelid='tbl2'::regclass and attnum>=1 and not attisdropped
)
select t1.*,t2.* from t1 full outer join t2 on (t1.attname = t2.attname and t1.typ=t2.typ and t1.attlen=t2.attlen) where t1.* is null or t2.* is null;

 attrelid | attname | atttypid | attlen | atttypmod | attrelid | attname | atttypid | attlen | atttypmod
----------+---------+----------+--------+-----------+----------+---------+----------+--------+-----------
    24675 | c2      |     1114 |      8 |        -1 |          |         |          |        |
          |         |          |        |           |    24681 | c01     |       23 |      4 |        -1
          |         |          |        |           |    24681 | c00     |       23 |      4 |        -1
          |         |          |        |           |    24681 | c0      |       23 |      4 |        -1
          |         |          |        |           |    24681 | c2      |     1184 |      8 |        -1
(5 rows)

长度不同也可以比对出来
postgres=# alter table tbl1 add column n1 numeric(10,2);
ALTER TABLE
postgres=# alter table tbl2 add column n1 numeric(10,3);
ALTER TABLE

使用format_type格式化一下类型, 更友好的输出
postgres=# with
t1 as (
select attrelid,attname,attlen,format_type(atttypid,atttypmod) as typ from pg_attribute where attrelid='tbl1'::regclass and attnum>=1 and not attisdropped
),
t2 as (
select attrelid,attname,attlen,format_type(atttypid,atttypmod) as typ from pg_attribute where attrelid='tbl2'::regclass and attnum>=1 and not attisdropped
)
select t1.*,t2.* from t1 full outer join t2 on (t1.attname = t2.attname and t1.typ=t2.typ and t1.attlen=t2.attlen) where t1.* is null or t2.* is null;
 attrelid | attname | attlen |             typ             | attrelid | attname | attlen |           typ
----------+---------+--------+-----------------------------+----------+---------+--------+--------------------------
    24675 | c2      |      8 | timestamp without time zone |          |         |        |
    24675 | n1      |     -1 | numeric(10,2)               |          |         |        |
          |         |        |                             |    24681 | c0      |      4 | integer
          |         |        |                             |    24681 | n1      |     -1 | numeric(10,3)
          |         |        |                             |    24681 | c00     |      4 | integer
          |         |        |                             |    24681 | c01     |      4 | integer
          |         |        |                             |    24681 | c2      |      8 | timestamp with time zone
(7 rows)

如果你还需要比对其他的不同之处, 例如约束, 字段顺序, 触发器等, 建议用pg_dump将两个表的定义导出, 然后diff一下.
或者研究一下pg_dump源码, 看看能不能找到更好的方法.
时间: 2024-09-20 00:32:03

PostgreSQL 如何比较两个表的定义是否一致的相关文章

PostgreSQL教程(一):数据表详解_PostgreSQL

一.表的定义:     对于任何一种关系型数据库而言,表都是数据存储的最核心.最基础的对象单元.现在就让我们从这里起步吧.     1. 创建表:   复制代码 代码如下:     CREATE TABLE products (         product_no integer,         name text,         price numeric     );         2. 删除表:   复制代码 代码如下:     DROP TABLE products;      

查询问题 急急急-查询两个表的数据,然后第一个表的数据存在相同时,则只显示一行,其他的显示为空

问题描述 查询两个表的数据,然后第一个表的数据存在相同时,则只显示一行,其他的显示为空 如上图,第一个表的字段包含 内码.编号.客户.日期,第二个表包含出库单等字段,现在查询出来的数据,只要内码相同,则对应的内码.编号.客户.日期都显示为空,该如何写SQL语句,原SQL语句如下 select t1.内码,t1.编号,t1.客户,t1.日期,t2.出库单 from SEOrder t1 join icstockbill t2 on t1.FInterID=t2.FInterID 解决方案 dani

关联到两张表,如何写触发器

问题描述 关联到两张表,如何写触发器 要求:数据在insert 到表A前(一笔一笔Insert),如果表A的字段1的值存在于表B中的字段2中,则报错,数据无法insert到表A中.这个触发器要怎么写呢.高人指点下.. 解决方案 已经找到方法了.如下,其中定义的变量为m一开始定义成connt还不行... create or replace trigger INSERT_AA before insert on aa For Each Rowdeclare -- local variables her

MySQL 麻烦大家帮我看看下面的两张表如何创建?

问题描述 MySQL 麻烦大家帮我看看下面的两张表如何创建? CREATE TABLE store ( store_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, manager_staff_id TINYINT UNSIGNED NOT NULL, address_id SMALLINT UNSIGNED NOT NULL, last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDA

sql语句-如何用SQL语句实现两张表(无关联)查询后,分别将各自的一个字段,插入一个新表。

问题描述 如何用SQL语句实现两张表(无关联)查询后,分别将各自的一个字段,插入一个新表. 有A.B.C三张表如下, 表 A 表B 学生ID(主键) 学生名称 课程ID(主键)| 课程名称 表 C 学生ID 课程ID (联合主键) 那么,通过SQL语句操作如何用学生姓名和课程名(只能获取学生姓名和课程名)将课程ID和学生ID插入到C表(C表中有课程ID和学生ID并且是联合主键),感激不尽. 解决方案 你可以定义2个变量,分别从表A表B用名称查询到ID.在表C的新增语句中使用这2个变量. 不过你这

序列-Orcale中 存在关联的两个表,怎么同时插入数据??

问题描述 Orcale中 存在关联的两个表,怎么同时插入数据?? 现在通过JDBC连接数据库,数据库中有两张表,存在主外键关系插入一条数据,另一张表就要插入多条,中间通过一个oid字段连接.这个字段是通过序列自增序列,现在的问题是,我怎么在存入数据的时候,再取出来这个自增的序列oid,这样好让我去另一张表里对应插入 5条数据. 解决方案 http://blog.sina.com.cn/s/blog_9844f5d901014h8n.html 解决方案二: 有知道应该怎么操作的吗??就是要取出来刚

学生上机信息统计——对两张表的联合查询

     在学生上机信息统计中,   此处,因为要查询两张表,而且两张表查询的先后有时要严格表明,所以,在查询时,有两种思路:      1,定义两个Recordset对象,并根据字段,判断是先查询学生信息表,还是先查询学生上机表      2,两张表有一个共同的字段:卡号,所以,可以根据卡号将两张表连起来查询,这样比较方便.    因为第一种方式比较复杂,容易出错,所以,我选择了第二种方式,将两张表联合起来.      下面是对两张表联合起来的查询的语句:   查询结果如下:   但是,,实际

Merge(在一条语句中使用Insert,Update,Delete) 对两个表进行同步数据

SQL Server 2008提供了一个增强的SQL命令Merge,用法参看MSDN:http://msdn.microsoft.com/zh-cn/library/bb510625.aspx 功能:根据与源表联接的结果,对目标表执行插入.更新或删除操作.例如,根据在另一个表中找到的差异在一个表中插入.更新或删除行,可以对两个表进行同步. 我们看一个例子,假如,有一总产品列表,一个分店产品列表,需要从分店添加产品时更新总产品列表. 总产品表,分店产品表结构完全一致: if OBJECT_ID('

查询两个表中字段个数不同,名称不同的SQL语句

语句 此sql语句能对两个不同表不同结构不同字段进行查询,并且能分出哪个记录是属于哪个表中的 有两个表table1结构如下id title content table2结构如下id content bigclass smallclass sql="select id, title, content,'' as bigclass,'' as smallclass, 'tbl1' as tbl from table1 where title like '%"&keyword&