使用debian的Postgres10.4.2(实际上,使用postgresql docker容器)
我有一些模式文件,我申请顺序。它们创建、删除和更改表,以跟踪模式随时间的变化。
然后,运行一个程序,该程序从PGYCub目录中选择表定义,以生成现有表的代码包装器。到目前为止,这个方法还不错。(这个程序的代码是由我开发的,因此非常可疑!)
我最近将“alter table customer add field customer_stem varchar(255)not null default'”和“create index on customer(customer_stem)”添加到一个新的模式文件中。
现在,在查找主键的表的查询中不再找到customer表。
我运行的查询是:

    select c.relname, i.indkey
    from pg_catalog.pg_index i
    inner join pg_catalog.pg_class c
      on i.indrelid=c.relfilenode
    inner join pg_catalog.pg_tables t
      on c.relname=t.tablename
    where t.schemaname='public'
      and i.indisprimary;

这应该告诉我哪些索引是表的主键。
然而,“customer”表现在从这个查询中掉了出来——pg_类中的relfilenode不再匹配pg_索引中的任何内容。
# select relname, relfilenode from pg_catalog.pg_class where relname='customer';
 relname  | relfilenode
----------+-------------
 customer |       16512

observe_dev=# select count(1) from pg_catalog.pg_index where indrelid=16512;
 count
-------
     0
(1 row)

这个表应该有一个主键和一个辅助索引!
所以,我的猜测是,“alter table”语句以某种方式改变了“customer”类的ID,使得它不再匹配“pg_index”表,但这看起来真的很奇怪。PSQL仍然知道定义是什么:
                                                    Table "public.customer"
    Column     |          Type          | Collation | Nullable |        Default        | Storage  | Stats target | Description
---------------+------------------------+-----------+----------+-----------------------+----------+--------------+-------------
 customer_id   | integer                |           | not null |                       | plain    |              |
 customer_name | character varying(255) |           | not null |                       | extended |              |
 customer_stem | character varying(255) |           | not null | ''::character varying | extended |              |
Indexes:
    "customer_pkey" PRIMARY KEY, btree (customer_id)
    "customer_customer_name_idx" btree (customer_name)
    "customer_customer_stem_idx" btree (customer_stem)
Referenced by:

还有一些外交关键关系。
所以,有两件事正在发生:
1)alter表以某种方式导致pg_目录停止保持最新(这似乎不太可能)
2)我对如何查找每个表的主键列的研究是错误的,而且我在查找错误的表/列
很有可能是2),但如果是,我应该如何找到这些信息?

最佳答案

我认为您应该加入pg_index专栏,即:

select c.relname, i.indkey
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
  on i.indrelid=c.oid  -- << HERE change c.relfilenode to c.oid
left join pg_catalog.pg_tables t
  on c.relname=t.tablename
where t.schemaname='public'
  and i.indisprimary;

注意pg_class.oidoidselect * from pg_catalog.pg_class\d pg_catalog.pg_class中的输出是隐藏的,但它是以“隐藏”列的形式存在的。
我能够在本地复制您的问题,所以我猜添加列或索引会更改表的psql记录中relfilenode的值。
另请参见https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns其中详细说明了如何查询主键-可能需要在join中添加到pg_class。不过,我发现值得注意的是,PostgreSQL将pg_attribute转换成了适当的'my_table_name'::regclass。实际上,您可以通过运行pg_class.oid来测试(并获取任何表的oid)!
为了方便起见,我还做了一些进一步的测试,以确定是哪个表更改触发了select 'my_table_name'::regclass::oid更改。原因似乎是默认的“pg_class.relfilenode”。
添加列而不指定alter table add column ...时,该值保持不变。以下脚本演示了该行为:
create table test (id uuid, col1 varchar(255));
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col2 varchar(255) not null;
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col3 varchar(255) not null default '';
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
drop table test;

因此,添加具有默认值的列似乎会由于某种原因更改关系的filenode。有关default和其他属性的更多详细信息,也值得阅读PostgreSQL docs on pg_class

关于sql - 为什么我的表从pg_catalog.pg_class中消失了? (或者,如何查找主键列?),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51886387/

10-11 02:29
查看更多