【问题标题】:Postgres conditional unique constraintPostgres 条件唯一约束
【发布时间】:2017-07-07 10:07:15
【问题描述】:

假设我有一个用户表,其中用户是特定租户的成员,并且他们的电子邮件被唯一地索引到他们的租户,如下所示:

User
id  |  tenant_id  |  email
1      1             person1@example.com
2      1             person2@example.com

允许此用户,因为尽管有重复的电子邮件,但他们位于不同的租户:

3      2             person1@example.com

此用户被阻止,因为同一租户的电子邮件重复:

4      2             person1@example.com <--- will throw an error

我们用唯一索引覆盖了这么多——这部分很简单。

现在假设我希望能够添加一个可以访问所有租户的全局用户,但前提是该电子邮件根本不存在于表中。此外,一旦记录存在,其他任何人(无论是否租用)都无法使用相同的电子邮件。

为了清楚起见,全局用户可以简单地拥有一个空租户 ID,但我们可能还会添加一个 global 布尔值。

有没有办法为这个逻辑编写约束?您不能简单地使电子邮件全局唯一地受到约束,因为它们将无法在租户之间重复,并且如果您使用空租户 ID 进行索引,如果存在具有相同 e 的租户用户,postgres 将允许未租户用户- 邮件。

我查看了排除约束和检查,但不知道如何组合它们(如果tenant_id 为空,则全局唯一地约束电子邮件,并在插入任何记录时检查具有空租户 ID 和匹配电子邮件的记录记录)。

请不要问我为什么要这样做——我的表实际上不是用户,我们已经考虑并驳回了其他架构:)

提前致谢!

【问题讨论】:

  • 为什么不是(电子邮件、租户)的唯一索引?
  • 正如我所说的“他们的电子邮件被唯一地索引到他们的租户”——我们已经涵盖了第一部分,这很容易。问题是关于第二部分的。

标签: postgresql unique-constraint postgresql-9.4 rails-postgresql unique-index


【解决方案1】:

根据 PostgreSQL 文档,您可以创建 unique partial index,这实际上与在您的表上创建唯一部分约束相同:

CREATE UNIQUE INDEX some_index ON some_table (col_a) WHERE (col_b is null);

使用此技术,您可以为管理员和非管理员用户创建 2 个单独的唯一索引。

【讨论】:

    【解决方案2】:

    您可以对这两个字段使用 UNIQUE 约束:

    create table myUsers
    (
        id int not null,
        tenant int not null,
        email varchar(200) not null,
        UNIQUE(email, tenant)
    );
    
    insert into myUsers values
    (1, 1, 'person1@example.com'),
    (2, 1, 'person2@example.com');
    
    insert into myUsers values
    (3, 2, 'person1@example.com');
    

    下一次插入会报错:

    insert into myUsers values
    (4, 2, 'person1@example.com');
    

    错误、警告:

    23505:重复键值违反唯一约束 “myusers_email_tenant_key”

    在这里查看:http://rextester.com/AJZVI34616

    对于问题的第二部分:

    现在假设我希望能够添加一个可以访问所有租户的全局用户,但前提是该电子邮件根本不存在于表中。

    一种解决方案是为管理员用户保留租户:

    tenant = 0  <-- admin users
    

    但 UNIQUE 约束允许重复的电子邮件,我建议您在此表中添加一个 rol 字段,或者为此目的使用另一个管理员用户表。

    在我的例子中,我们使用两个表,并且都有一个rol 字段。

    【讨论】:

    • 感谢您的回答,我应该更清楚我们已经涵盖了第一部分——这很容易。回复:第二部分,正如我所指出的,该表实际上并不是针对用户的,虽然我们考虑了替代架构,但对于我们的代码来说,这是迄今为止最干净的。只是想了解我提到的限制是否可行。
    • * “是可能的”(不是“我们可能的”)
    猜你喜欢
    • 2015-03-06
    • 1970-01-01
    • 2010-10-26
    • 2013-04-20
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多