两个相互引用的 postgresql 表
Two postgresql tables referencing each other
问题可能很基础,我对数据库没有任何经验。
我有一个带有一些 table 的 postgres 数据库。其中两个是 dates
和 accounts
.
date
table 有一个 account_id
字段引用 id
table 在 account
table 和一个balance
表示该帐户在该日期的余额的字段。因此,许多 date
个实体可以引用一个 account
个实体,多对一,好吧。
但是 account
table 也有一个 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
);
P.S。我使用 init.sql 创建 tables,但使用 sqlalchemy 与它们一起工作,如果有人也可以展示如何用它定义这样的模型,那就太好了。
如所写,SQL 脚本永远不会工作,原因有二:
外键只能引用table的主键,不能引用其中的任意列。所以 actual_date_id 应该是一个 integer
以便能够引用 dates
table.
的主键
您不能引用尚未创建的table,因此帐户和日期之间的外键必须在两个table都创建后创建.
使用循环外键,通常更容易将其中至少一个定义为可延迟的,这样您就可以插入它们而无需例如中间 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;
一开始就避免循环引用可能会更好。由于您想确保每个帐户只存在一个“当前余额”,这可以通过在日期 table 中添加一个标志并在帐户 [=51] 中删除 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 版本,recommended 使用 identity
列而不是 serial
问题可能很基础,我对数据库没有任何经验。
我有一个带有一些 table 的 postgres 数据库。其中两个是 dates
和 accounts
.
date
table 有一个 account_id
字段引用 id
table 在 account
table 和一个balance
表示该帐户在该日期的余额的字段。因此,许多 date
个实体可以引用一个 account
个实体,多对一,好吧。
但是 account
table 也有一个 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
);
P.S。我使用 init.sql 创建 tables,但使用 sqlalchemy 与它们一起工作,如果有人也可以展示如何用它定义这样的模型,那就太好了。
如所写,SQL 脚本永远不会工作,原因有二:
外键只能引用table的主键,不能引用其中的任意列。所以 actual_date_id 应该是一个
的主键integer
以便能够引用dates
table.您不能引用尚未创建的table,因此帐户和日期之间的外键必须在两个table都创建后创建.
使用循环外键,通常更容易将其中至少一个定义为可延迟的,这样您就可以插入它们而无需例如中间 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;
一开始就避免循环引用可能会更好。由于您想确保每个帐户只存在一个“当前余额”,这可以通过在日期 table 中添加一个标志并在帐户 [=51] 中删除 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 版本,recommended 使用 identity
列而不是 serial