簡體   English   中英

Postgres條件唯一約束

[英]Postgres conditional unique constraint

假設我有一個用戶表,其中用戶是特定租戶的成員,他們的電子郵件是唯一索引到他們的租戶,如下所示:

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為null,則全局唯一地約束電子郵件,並在插入任何記錄時檢查具有空租戶ID和匹配電子郵件的記錄)。

請不要問為什么我這樣做 - 我的桌子實際上不是用戶,我們已經考慮並解雇了其他架構:)

提前致謝!

根據PostgreSQL文檔,您可以創建唯一的部分索引 ,這與在表上創建唯一的部分約束實際上相同:

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

使用此技術,您可以為管理員和非管理員用戶創建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字段,或者為此目的使用另一個admin用戶表。

在我的例子中,我們使用兩個表,並且都有一個rol字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM