假设我们有用户,每个用户可以有多个电子邮件地址
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
我想向一个非常大的表添加一个检查约束。就像是:
ALTER TABLE "accounts" ADD CONSTRAINT "positive_balance" CHECK ("balance" >= 0);
Run Code Online (Sandbox Code Playgroud)
不幸的是 PostgreSQL 9.3 在约束检查完成之前阻止读取或写入。我通过启动一个事务,运行ALTER TABLE,然后打开第二个事务并检查在第一个事务完成之前我无法从表中读取或写入来验证这一点。
有什么办法可以在CHECK不锁定表的情况下添加此约束?
我正在尝试同时创建一个索引。
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?
假设我有一个像这样的数据库模式
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?
如果您使用事务,会锁定您读取的行吗?