繁体   English   中英

两个互相引用的 postgresql 表

[英]Two postgresql tables referencing each other

问题可能是基本的,我对数据库没有任何经验。

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

date表有一个account_id字段引用account表中的一个id表和一个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
);

PS 我使用 init.sql 创建表,但使用 sqlalchemy 与它们一起工作,如果有人也能展示如何用它定义这样的 model,那就太好了。

正如所写的 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,
    account_id INT REFERENCES accounts,
    is_current_balance boolean not null default false,
    date DATE,
    balance INT,
    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 版本, 建议使用identity列而不是serial

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM