微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

两个相互引用的 postgresql 表

如何解决两个相互引用的 postgresql 表

问题可能很基础,我对数据库没有任何经验。

我有一个带有一些表的 postgres 数据库。其中两个是 datesaccounts

date 表有一个 account_id 字段引用 id 表中的 account 表和一个 balance 字段表示帐户在那个日期。因此,许多 date 实体可能会引用一个 account 实体,多对一,可以。

但是 account 表也有一个 actual_date 字段,该字段必须引用 date 实体,以及该帐户的实际余额。一个 account 实体可能引用一个实际的 date 实体,但 date 实体可以有一个或零个 account 实体引用它。如果它确实有一个actual_date 引用它的帐户,它将始终是同一个帐户,date 本身用 account_id 引用。

这是什么关系?甚至有可能实施吗?如果是,我该怎么做?

我想出了这段代码,但我不知道它是否符合我的想法。

CREATE TABLE accounts (
    id SERIAL PRIMARY KEY,user_id INT REFERENCES users,actual_date_id DATE UNIQUE REFERENCES dates
);
CREATE TABLE dates (
    id SERIAL PRIMARY KEY,account_id INT REFERENCES accounts,date DATE,balance INT,unconfirmed_balance INT
);

附言我使用 init.sql 创建表,但使用 sqlalchemy 使用它们,如果有人也能展示如何用它定义这样的模型,那就太好了。

解决方法

由于两个原因,SQL 脚本永远不会运行:

  1. 外键只能引用表的主键,不能引用表中的任意列。所以actual_date_id 应该是一个integer,以便能够引用dates 表的主键。

  2. 您不能引用尚未创建的表,因此帐户和日期之间的外键必须在创建两个表后创建。

使用循环外键通常更容易将它们中的至少一个定义为可延迟的,这样您就可以插入它们而无需例如中间 NULL 值。

所以有些东西(假设 users 已经存在)

CREATE TABLE accounts (
    id SERIAL PRIMARY KEY,user_id INT REFERENCES users,actual_date_id integer UNIQUE -- note the data type
);

CREATE TABLE dates (
    id SERIAL PRIMARY KEY,account_id INT REFERENCES accounts,date DATE,balance INT,unconfirmed_balance INT
);

-- now we can add the foreign key from accounts to dates
alter table accounts
  add foreign key (actual_date_id)
  references dates (id)
  deferrable initially deferred;

一开始最好避免循环引用。由于您想确保每个帐户只有一个“当前余额”,因此可以通过在日期表中添加一个标志并去掉帐户表中的 actual_date_id 来实现。

CREATE TABLE accounts (
    id SERIAL PRIMARY KEY,user_id INT REFERENCES users
);

CREATE TABLE dates (
    id SERIAL PRIMARY KEY,is_current_balance boolean not null default false,unconfirmed_balance INT
);

-- this ensures that there is exactly one row with "is_current_balance = true" 
-- for each account 
create unique index only_one_current_balance 
   on dates (account_id)
   where is_current_balance;

在将 dates 中的一行更改为“当前行”之前,您需要将现有行重置为 false


不相关,但是:

在现代 Postgres 版本中,recommended 使用 identity 列而不是 serial

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。