信息模式中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 值 的相关文章

  • MySQL“LIKE”搜索不起作用

    我通过 LOAD DATA INFILE 在 MySQL 中导入了一个 txt 数据库 一切似乎都正常 唯一的问题是 如果我使用以下查询在数据库上搜索记录 SELECT FROM hobby WHERE name LIKE Beading
  • 从 PostgreSQL 中同一列中以其他值开头的列中检索所有值的有效方法

    为了简单起见 假设您有一个包含如下数字的表 number 123 1234 12345 123456 111 1111 2 700 检索最短数字的有效方法是什么 称它们为roots或其他 和所有值derived来自他们 例如 root de
  • PostgreSQL 中的 Long 数据类型相当于什么?

    我想知道相当于什么LongPostgreSQL 中的数据类型 根据the docs http www postgresql org docs 7 4 interactive datatype html DATATYPE INT看起来像big
  • 只获取倒数第二条记录 - mysql-query

    我有一个如下表记录 my table id rating description 1 0 0 bed 2 1 0 good 3 0 0 bed 4 1 0 good 5 0 0 bed 6 0 0 bed 7 0 0 bed 现在我通过评级
  • 需要按天分割日期时间范围

    我有一个需要根据日期时间拆分的表 输入表 ID Start End A 2019 03 04 23 18 04 2019 03 04 23 21 25 A 2019 03 04 23 45 05 2019 03 05 00 15 14 所需
  • SQL 中基于下一条记录和上一条记录的复杂排序

    这是一个后续问题根据 SQL 中的下一条记录和上一条记录进行排序 https stackoverflow com questions 30477803 sorting based on next and previous records i
  • 加密数据库字段的好方法?

    我被要求加密数据库中的各种数据库字段 问题是这些字段在读取后需要解密 我在用着Django and SQL Server 2005 有什么好主意吗 See 在 SQL Server 2005 数据库中使用对称加密 https web arc
  • Mac OSX Lion Postgres 不接受 /tmp/.s.PGSQL.5432 上的连接

    我在 Homebrew 安装 Postgres 时遇到常见的 Mac OSX 错误 No such file or directory Is the server running locally and accepting connecti
  • sql查询获取从一月到当月的所有数据,即使没有记录

    我不擅长 sql 所以任何帮助世界都很棒 我有一个 SQL 查询 可以获取从一月到当月注册的记录 我的代码示例 SELECT DatePart YEAR p createStamp as TheYear DatePart MONTH p c
  • Reporting Services 在哪里存储其日志文件

    最相关的谷歌结果似乎表明 为了访问日志 我们必须将您自己的日志表部署到数据库并制作报告服务写入它 http technet microsoft com en us library ms157403 aspx 简而言之 Reporting S
  • PostgreSQL-过滤日期范围

    我是一名 SQL 开发人员 大部分时间都花在 MSSQL 上 我正在寻找一种更好的方法来过滤 PostgreSQL 数据库中的 无时区时间戳 字段 我在用着 Where DateField gt 2010 01 01 and DateFie
  • MySQL中如何声明变量?

    如何在mysql中声明一个变量 以便我的第二个查询可以使用它 我想写一些类似的东西 SET start 1 SET finish 10 SELECT FROM places WHERE place BETWEEN start AND fin
  • 快速查询最新记录的方法?

    我有一张这样的表 USER PLAN START DATE END DATE 1 A 20110101 NULL 1 B 20100101 20101231 2 A 20100101 20100505 在某种程度上 如果END DATE i
  • st_intersects 与 st_overlaps

    这两个查询有什么区别 select a gid sum length b the geom from polygons as a roads as b where st intersects a the geom b the geom gr
  • 如何通过 SQL 表关联 SQL 中的实体

    我是数据库设计的初学者 我需要为项目创建数据库 我可以用面向对象的术语解释我想要做什么 值得庆幸的是 数据库专家会很友善地向我解释如何在数据库方面处理这个问题 我想创建一个与位置实体 州 城市 有关系的用户 ID 名称 实体 所以在编程语言
  • 使用子查询 select 创建新表

    我试图从子查询选择创建一个新表 但出现以下错误 附近的语法不正确 SELECT INTO foo FROM SELECT DATEPART MONTH a InvoiceDate as CalMonth DATEPART YEAR a In
  • SELECT max(x) 返回 null;我怎样才能让它返回0?

    运行以下命令时如何返回 0 而不是 null SELECT MAX X AS MaxX FROM tbl WHERE XID 1 假设没有XID 1的行 or SELECT coalesce MAX X 0 AS MaxX FROM tbl
  • MYSQL从每个类别中随机选择一条记录

    我有一个数据库Items表看起来像这样 id name category int 有几十万条记录 每个item可以是 7 种不同的之一categories 对应于categories table id category 我想要一个从每个类别
  • mysql自动存储记录创建时间戳

    mysql 有什么方法可以在创建记录时自动将时间戳存储在记录行中 我试图使用时间戳 数据类型 和 current timestamp 作为默认值 但后来意识到每次更新记录时都会更新 我只需要一些可以存储创建时间戳的东西 Thanks Set
  • 是否可以引用同一个表中的不同列?

    如果博客有一个 类别 表 如下所示 CREATE TABLE categories id INTEGER PRIMARY KEY AUTO INCREMENT parent id INTEGER NOT NULL name VARCHAR

随机推荐