我们的PostgreSQL 11数据库有表A和表B.

postgres=# \d A;
                              Table "public.A"
       Column        |            Type             | Collation | Nullable | Default 
---------------------+-----------------------------+-----------+----------+---------
 id                  | bigint                      |           | not null | 
 b_id                | bigint                      |           | not null | 
 
Indexes:
    "a_pkey" PRIMARY KEY, btree (id)
    "idx_a_bid" btree (b_id)
Foreign-key constraints:
    "fk_a_bid" FOREIGN KEY (b_id) REFERENCES A(id)

postgres=# select count(*) from A where b_id = 522039;
 count 
-------
    90
(1 row)
                  
postgres=# select count(*) from B where id = 522039;
 count 
-------
     0
(1 row)

似乎有一个从a.b_id到b.id的非强制FK.

这些表上的触发器从未被禁用(因此在理论上已经应用了FK判断).

除了过go 有人禁用触发器并从B中删除行之外,还有什么原因可以解释这一点?

推荐答案

什么会使PostgreSQL违反外键约束?有三个可能的答案,每个答案都与外键由系统触发器在被引用表和引用表上实现这一事实有关.这些触发器没有显示在\dtinformation_schema.triggers的输出中,您必须查询目录pg_trigger才能看到它们.

Violate a foreign key by setting session_replication_role

如果为session_replication_role = replica,则正常的触发器不会触发.只有使用以下语句中的ON更改的触发器才会触发:

ALTER TABLE ... ENABLE REPLICA TRIGGER ...
ALTER TABLE ... ENABLE ALWAYS TRIGGER ...

超级用户需要更改session_replication_role,并且需要超级用户修改实现外键的系统触发器.

禁用表上的触发器违反外键约束

这可以通过以下方式完成

ALTER TABLE ... DISABLE TRIGGER ALL

在引用表或引用表上.此语句只能由超级用户执行.根据您是否禁用了被引用表或引用表上的触发器,将不再判断外键约束的某些方面.

使用用户定义的触发器违反级联外键

使用创建约束

ALTER TABLE a ADD FOREIGN KEY (b_id) REFERENCES b (id) ON DELETE CASCADE;

然后创建如下触发器:

CREATE FUNCTION cancel_delete() RETURNS trigger
   LANGUAGE plpgsql AS
$$BEGIN
   RETURN NULL;
END;$$;

CREATE TRIGGER cancel_delete BEFORE DELETE ON a
   FOR EACH ROW EXECUTE FUNCTION cancel_delete();

现在,如果您删除b中的一行,系统触发器将删除a中的行,但您创建的触发器将不会出错地中止这些删除,因为它返回NULL.这将 destruct 引用完整性.

创建损坏的外键的异国方式

  • 您可以创建NOT VALID个外键约束(但这将在\d中显示)

  • 您可能会遇到数据损坏,其中一个表中的数据会自动丢失

  • 您可以直接修改目录,例如,在pg_constraint中插入一行

那么是什么原因导致外键被 destruct 呢?

前两种方法要求超级用户做一些错误的事情,但第三种方法对普通用户开放.如果您可以排除超级用户篡改数据库的可能性,那么它一定是第三种方法.

Postgresql相关问答推荐

无法从Docker迁移Golang上的两个不同服务到一个数据库'

在Go中,如何在没有数据库包的情况下运行PostgreSQL查询?

使用Spring data jpa和CriteriaQuery在jsonb列中搜索操作

使用jOOQ在postgres上取消嵌套enum_range

如何创建一个触发器来传播对主键表的更新?

Postgresql如何从jsonB列的数组中的多个json中 Select 一个值

Postgis 不只使用索引扫描

postgresql 更新错误ERROR: invalid input syntax for type boolean:

查询仅属于特定部门的用户

如何将1 天 01:30:00等间隔转换为25:30:00?

Select 中的 PostgreSQL 正则表达式捕获组

PostgreSQL:使用 psql 命令行实用程序时 Windows 上的编码问题

无法使用 sequelize 从本地 node 应用程序连接到 heroku postgresql 数据库

将数据从 MS SQL 迁移到 PostgreSQL?

如何增加 max_locks_per_transaction

获取json列键为空的记录

Postgres Hstore 与 Redis - 性能方面

错误:关系列不存在 PostgreSQL,无法运行插入查询

如何在postgresql中编写关于最大行数的约束?

如何在创建数据库时安装 Postgres 扩展?