信息架构中referential_constraints.unique_constraint_ *列的NULL值

问题描述 投票:2回答:1

在Postgres 10中,我声明了以下内容:

create table test_abc (
    pk integer not null,
    id integer not NULL,
    id2 integer not null,
    PRIMARY KEY (pk)
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);

然后是第二个表,其中有一个FK引用第一个表:

create table test_def (
    id integer not null,
    abc_id integer,
    abc_id2 integer,
    PRIMARY KEY (id),
    FOREIGN KEY (abc_id,abc_id2) references test_abc(id,id2)
);

现在考虑此查询的输出:

SELECT unique_constraint_catalog, unique_constraint_schema, unique_constraint_name
FROM   information_schema.referential_constraints r
WHERE  r.constraint_name = 'test_def_abc_id_fkey'
----------------------
NULL NULL NULL

所有unique_constraint_*列均为空值。

Postgres documentation起,似乎这些元列应包含

[对象的名称,其中包含外键约束引用的唯一或主键约束(始终是当前数据库)

问题:我肯定在同一个数据库中,并且在test_abc表上声明的唯一索引是唯一约束(否则我将无法声明FK开头),那么为什么这些列为空?

我正在使用referential_constraints和一些联接来获取有关我的外键引用的列的信息,但是这样一来,我会丢失所有使用索引设置唯一约束的列。

sql postgresql foreign-keys information-schema database-metadata
1个回答
0
投票

测试设置

您假设约束名称为test_def_abc_id_fkey,这是您在Postgres 11或更早版本中的设置所产生的默认名称。但是,值得注意的是,Postgres 12的默认名称已得到改进,在test_def_abc_id_abc_id2_fkey中使用相同的设置。 The release notes for Postgres 12:

  • 为外键选择默认约束名称时使用所有键列的名称(Peter Eisentraut)

    以前,约束名称中仅包含第一列名称,从而导致多列外键不明确。

参见:

db <>小提琴here

所以让我们对FK约束使用显式名称test_def_abc_fkey以避免混淆:

CREATE TABLE test_abc (
  pk  int PRIMARY KEY
, id  int NOT NULL
, id2 int NOT NULL
);

CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);

CREATE TABLE test_def (
  id      int PRIMARY KEY
, abc_id  int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey  -- !
     FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);

还有那个works in Postgres 9.5 - Postgres 12.Even in Postgres 9.3.(我一直有错误的印象,需要实际的constraint。)

答案

您从查询信息模式中得到的观察结果成立:

SELECT *
FROM   information_schema.referential_constraints
WHERE  constraint_name = 'test_def_abc_fkey';  -- unequivocal name

我们得到一行,但是三个字段unique_constraint_catalogunique_constraint_schemaunique_constraint_nameNULL

解释似乎很简单。如手册所述,这些专栏描述了:

...外键约束引用的唯一或主键约束

但是没有UNIQUE constraint,只有UNIQUEUNIQUE index约束是使用Postgres中的UNIQUE索引实现的。约束由SQL标准定义,索引是实现细节。存在与您发现的差异之间的差异。相关:

  • UNIQUE

与实际UNIQUE相同的测试约束按预期显示数据:

db <>小提琴How does PostgreSQL enforce the UNIQUE constraint / what type of index does it use?

所以这似乎很有意义。尤其是由于UNIQUE也由SQL标准委员会定义,并且索引没有标准化,仅是约束。 (信息模式视图中没有索引信息。)

都清楚吗?不完全是。

但是

[还有另一个信息模式视图here。其最后一列描述为:

information schema ...对于外键约束,所引用列在其唯一constraint中的顺序位置(计数从1开始);否则为null

Bold强调我的。在此,无论如何,列在index中的顺序位置:

key_column_usage

参见:

db <>小提琴key_column_usage

似乎不一致。

更糟糕的是,position_in_unique_constraint声称创建SELECT * FROM information_schema.key_column_usage WHERE constraint_name = 'test_def_abc_fkey'; 约束将需要实际的herethe manual约束:

外键必须引用作为主键或形成独特的约束。这意味着引用的列总是有一个索引(作为主键或唯一索引的索引)约束);因此检查引用行是否匹配有效率。

似乎是一个文档错误?如果没有人指出我在哪里出了问题,我将提交一个错误报告。

相关:

  • PRIMARY KEY

解决方案

我正在使用UNIQUE和一些联接来获取有关我的外键引用的列的信息,但是这样一来,我会丢失所有使用索引设置唯一约束的列。

在Postgres中,系统目录是真实的真实来源。参见:

  • FOREIGN KEY

所以您可以使用类似的东西(例如我也在上面的Postgres unique constraint vs index中添加的内容:]]

referential_constraints

返回:

名| fk_table | fk_columns | ref_table | ref_key_columns:---------------- | :------- | :--------------- | :-------- | :--------------test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}

相关:

  • Information schema vs. system catalogs
  • fiddle
  • SELECT c.conname , c.conrelid::regclass AS fk_table, k1.fk_columns , c.confrelid::regclass AS ref_table, k2.ref_key_columns FROM pg_catalog.pg_constraint c LEFT JOIN LATERAL ( SELECT ARRAY ( SELECT a.attname FROM pg_catalog.pg_attribute a , unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord) WHERE a.attrelid = c.conrelid AND a.attnum = k.attnum ORDER BY k.ord ) AS fk_columns ) k1 ON true LEFT JOIN LATERAL ( SELECT ARRAY ( SELECT a.attname FROM pg_catalog.pg_attribute a , unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord) WHERE a.attrelid = c.confrelid AND a.attnum = k.attnum ORDER BY k.ord ) AS ref_key_columns ) k2 ON true WHERE conname = 'test_def_abc_fkey';
© www.soinside.com 2019 - 2024. All rights reserved.