小编Kev*_*rke的帖子

在数据库中强制执行“至少一个”或“恰好一个”的约束

假设我们有用户,每个用户可以有多个电子邮件地址

CREATE TABLE emails (
    user_id integer,
    email_address text,
    is_active boolean
)
Run Code Online (Sandbox Code Playgroud)

一些示例行

user_id | email_address | is_active
1       | foo@bar.com   | t
1       | baz@bar.com   | f
1       | bar@foo.com   | f
2       | ccc@ddd.com   | t
Run Code Online (Sandbox Code Playgroud)

我想强制执行一个约束,即每个用户都只有一个活动地址。我怎样才能在 Postgres 中做到这一点?我可以这样做:

CREATE UNIQUE INDEX "user_email" ON emails(user_id) WHERE is_active=true;
Run Code Online (Sandbox Code Playgroud)

这可以防止用户拥有多个活动地址,但我相信不会防止他们的所有地址都设置为 false。

如果可能的话,我更愿意避免使用触发器或 pl/pgsql 脚本,因为我们目前没有这些脚本,而且设置起来会很困难。但我很感激知道“唯一的方法是使用触发器或 pl/pgsql”,如果是这样的话。

postgresql database-design constraint referential-integrity ddl

28
推荐指数
3
解决办法
8683
查看次数

如何在不锁定表的情况下在 Postgres 中添加检查约束?

我想向一个非常大的表添加一个检查约束。就像是:

ALTER TABLE "accounts" ADD CONSTRAINT "positive_balance" CHECK ("balance" >= 0);
Run Code Online (Sandbox Code Playgroud)

不幸的是 PostgreSQL 9.3 在约束检查完成之前阻止读取或写入。我通过启动一个事务,运行ALTER TABLE,然后打开第二个事务并检查在第一个事务完成之前我无法从表中读取或写入来验证这一点。

有什么办法可以在CHECK不锁定表的情况下添加此约束?

postgresql constraint data-integrity

13
推荐指数
2
解决办法
8102
查看次数

如何确定并发 Postgres 索引被标记为 INVALID 的原因?

我正在尝试同时创建一个索引。

CREATE INDEX CONCURRENTLY blocks_expr_idx6 ON blocks USING btree ('blah') WHERE "type" = 'user root';
Run Code Online (Sandbox Code Playgroud)

运行查询 12 小时后,如果我运行\d blocksPostgres 报告索引无效:

"blocks_expr_idx6" btree ('blah') WHERE "type" = 'user root' INVALID
Run Code Online (Sandbox Code Playgroud)

文档说:

如果在扫描表时出现问题,例如死锁或唯一索引中的唯一性违规,CREATE INDEX 命令将失败,但会留下“无效”索引。出于查询目的,该索引将被忽略,因为它可能不完整;但是它仍然会消耗更新开销。psql \d 命令将报告这样的索引为 INVALID。

在这种情况下推荐的恢复方法是删除索引并再次尝试执行 CREATE INDEX CONCURRENTLY。(另一种可能性是使用 REINDEX 重建索引。但是,由于 REINDEX 不支持并发构建,因此该选项似乎不太吸引人。)

我怎样才能弄清楚为什么Postgres 将索引标记为 INVALID?

postgresql index

9
推荐指数
1
解决办法
3726
查看次数

Postgres 中匹配条件的行数上限

假设我有一个像这样的数据库模式

user_id text
photo_id text
date_created timestamp
Run Code Online (Sandbox Code Playgroud)

我想强制执行“一个用户只能拥有 30 张照片”的约束。实现这一点的一个天真的方法是

SELECT COUNT(*) FROM user_photos WHERE user_id='usr_123'
Run Code Online (Sandbox Code Playgroud)

将结果与 30 进行比较,如果较低,则进行插入。天真,因为如果您可以在短时间内触发多个请求,您就可以赢得一场比赛并最终写入 30 多个记录。

有没有办法在数据库中强制执行此约束?例如创建某种索引“只能插入 30 行”,或者什么?有没有办法让一个count列为每个 userId 单独递增,并且可以将其范围限制为0-29

如果您使用事务,会锁定您读取的行吗?

postgresql index constraint

7
推荐指数
2
解决办法
6005
查看次数