信息模式中referential_constraints.unique_constraint_* 列的NULL 值

2023-12-11

在 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

All unique_constraint_*列具有空值。

来自Postgres 文档看来这些元列应该包含

包含外键约束引用的唯一或主键约束的 [object] 的名称(始终是当前数据库)

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

我正在使用referential_constraints通过一些连接来获取有关外键引用的列的信息,但这样我就错过了使用索引设置唯一约束的所有那些信息。


测试设置

您假设约束名称test_def_abc_id_fkey,您在 Postgres 11 或更早版本中的设置产生的默认名称。不过,值得注意的是,Postgres 12 的默认名称已得到改进,相同的设置会导致test_def_abc_id_abc_id2_fkey. Postgres 12 的发行说明:

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

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

See:

数据库小提琴here

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

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)
);

然后适用于 Postgres 9.5 - Postgres 12, 即使在 Postgres 9.3 中也是如此。
(我一直有一种错误的印象约束将是必需的。)

Answer

您通过查询信息模式观察到的结果是:

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

我们得到一行,但是三个字段unique_constraint_catalog, unique_constraint_schema and unique_constraint_name are NULL.

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

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

但没有UNIQUE 约束,只是一个UNIQUE index. A UNIQUE约束是使用实现的UNIQUEPostgres 中的索引。约束由 SQL 标准定义,索引是实现细节。存在一些差异,就像您发现的那样。有关的:

  • PostgreSQL 如何强制执行 UNIQUE 约束/它使用什么类型的索引?

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

数据库小提琴here

所以这似乎是有道理的。尤其是自从信息图式也是由SQL标准委员会定义的,索引没有标准化,只有约束。 (信息架构视图中没有索引信息。)

全清?不完全的。

However

还有另一个信息模式视图key_column_usage。其最后一栏描述为:

position_in_unique_constraint...对于外键约束,引用列在其唯一的内部的顺序位置约束(计数从 1 开始);否则为空

Bold强调我的。这里,列在index无论如何都列出了:

SELECT *
FROM   information_schema.key_column_usage
WHERE  constraint_name = 'test_def_abc_fkey';

See:

数据库小提琴here

看起来不一致。

更糟糕的是,手册声称实际的PRIMARY KEY or UNIQUE创建一个约束将需要FOREIGN KEY约束:

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

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

Related:

  • Postgres 唯一约束与索引

Solution

我正在使用referential_constraints通过一些连接来获取有关外键引用的列的信息,但这样我就错过了使用索引设置唯一约束的所有那些信息。

在 Postgres 中,系统目录是实际的事实来源。看:

  • 信息模式与系统目录

所以你可以使用这样的东西(就像我也在fiddle above):

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';

Returns:



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

Related:

  • 使用表、字段和模式名称查找引用的表名称
  • 查找外键约束的引用字段
  • 如何找到通过外键引用特定行的表?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

信息模式中referential_constraints.unique_constraint_* 列的NULL 值 的相关文章

  • 创建用于插入、修改和删除的数据库触发器的正确​​语法是什么

    我有一个看起来像是 SQL Server 中数据库触发器的基本场景 但我遇到了一个问题 我有桌子Users 身份证 姓名 电话等 我有桌子用户历史记录 id user id 操作 字段 时间戳 我想要一个数据库触发器 可以随时插入 更新或删
  • 如何在 NHibernate 中自动生成 ID

    如何让 NHibernate 自动生成表的唯一 ID ID 可以是任意的long值 只要每个值仅使用一次 我当前的映射如下所示
  • oracle 数据透视表中的列

    示例选择 select from select 1 cnt 2 sm 55 name 12 month 2011 year 12 2011 mnth txt from dual union all select 1 cnt 2 sm 54
  • 如何设置外键id的id #sf2 #doctrine2

    我正在尝试手动为对象设置外键 id 但没有找到如何执行此操作 class Item ORM ManyToOne targetEntity MyBundle Entity ItemType inversedBy itemTypes ORM J
  • 选择表中的人员并排除妻子,但合并他们的名字

    我有一张桌子Person PersonID FirstName LastName 1 John Doe 2 Jane Doe 3 NoSpouse Morales 4 Jonathan Brand 5 Shiela Wife And a R
  • Postgres - 这是在布尔列上创建部分索引的正确方法吗?

    我有下表 CREATE TABLE recipemetadata Lots of columns diet glutenfree boolean NOT NULL 大多数每一行都会被设置为FALSE除非有人想出一些席卷全国的疯狂新无麸质饮食
  • 从 oracle 中为每个组选择最新行

    我在留言簿中有一张包含用户评论的表格 列有 id user id 标题 评论 时间戳 我需要为每个用户选择最新行 我尝试使用 group by 执行此操作 但没有管理它 因为我无法在按 user id 分组的同一查询中选择任何其他内容 SE
  • Sql 查询抛出标识符太长。最大长度为 128

    我正在处理一个简单的更新查询 在执行查询时看到以下错误 我非常清楚 这根本不应该是一个长度问题 可能是什么问题 Error 以identifier开头的标识符太长 最大长度为 128 我的查询 update dbo DataSettings
  • SQL:列出多个连接语句中的重复记录?

    你好 以下查询在连接多个表后返回所有员工 select e from dbo EMP e join dbo HREMP a on a ID e ID join dbo LOGO c on c EMPID e id join dbo LOGO
  • 使用 pg-promise 进行多行插入

    我想用一个插入多行INSERT查询 例如 INSERT INTO tmp col a col b VALUES a1 b1 a2 b2 有没有一种方法可以轻松地做到这一点 最好是对于像这样的对象数组 col a a1 col b b1 co
  • 导出 Azure SQL 数据库时出现错误 SQL71501

    导出 Azure SQL 数据库时出现奇怪的错误 导出一直工作正常 直到最近发生一些架构更改 但现在出现错误 SQL71501 该数据库是V12 兼容性级别130 尽管master数据库仍兼容级别 120 该问题似乎是由一个新的表值函数引起
  • Visual Studio 2008 (C#) 与 SQL Compact Edition 数据库错误:26

    与网络相关或特定于实例的 建立时发生错误 连接到 SQL Server 服务器 未找到或无法访问 验证实例名称是否为 正确并且 SQL Server 是 配置为允许远程 连接 提供商 SQL 网络 接口 错误 26 错误定位 指定服务器 实
  • 创建用于存储高尔夫球成绩的可扩展数据库架构

    我正在尝试设计一个数据库来存储我所有的朋友和我的高尔夫球成绩 您可能知道 高尔夫得分由 18 洞的个人得分组成 我可以想到两种设计模式的方法 创建一个表 每个洞有一列 例如 h1 到 h18 该表具有引用其他表的 FK player id
  • SQL查询多行变成单行

    有什么方法可以将通常返回具有相同值的多行的 SQL 查询更改为单行吗 例如 如果我现有的查询返回以下内容 ColA ColB 1 AA 1 BB 1 CC 2 AA 3 AA 我可以将查询更改为仅返回 3 行 并将 1 的第二个和第三个结果
  • 在触发器中记录更新操作

    我有一个 UPDATE 触发器 它生成 INSERTED 和 DELETED 表 如下所示 INSERTED Id Name Surname 1 Stack Overflow 2 Luigi Saggese DELETED Id Name
  • 寻找多列索引的最佳顺序

    假设我有一个包含两个索引的表 一个位于 a 列 一个位于 a b 和 c 列 我注意到 根据索引定义中列的顺序 MySQL 可能最终使用单列索引而不是多列索引 即使多列索引中的所有三列都在 ON 中引用JOIN 的一部分 这有点引出了一个问
  • 获取MySql中重复行的列表

    我有一张这样的桌子 ID nachname vorname 1 john doe 2 john doe 3 jim doe 4 Michael Knight 我需要一个查询 该查询将从具有相同 nachname 和 vorname 的记录
  • SQL:两个没有完整列匹配的表的并集

    我有一个table A其中有一组列A1 A2和一个具有一组列的 table bB1 B2 碰巧的是A2 B1但其余列不匹配 也不应该匹配 我想附加表格 所以我使用UNION ALL 对于不匹配的列 我使用null as COLUMN NAM
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • oracle日期序列?

    我有一个 oracle 数据库 我需要一个包含 2 年所有日期的表 例如来自01 01 2011 to 01 01 2013 首先我想到了一个序列 但显然唯一支持的类型是数字 所以现在我正在寻找一种有效的方法来做到这一点 欢呼骗局 如果您想

随机推荐