3

假裝我有一個用戶表,其中用戶是一個特定租戶的成員,他們的電子郵件是唯一收錄到自己的房客,是這樣的:Postgres的條件唯一約束

User 
id | tenant_id | email 
1  1    [email protected] 
2  1    [email protected] 

該用戶被允許的,因爲儘管一個重複的電子郵件,它們是在不同承租人:

3  2    [email protected] 

防止該用戶,因爲電子郵件是在相同的租戶重複:

4  2    [email protected] <--- will throw an error 

我們有這麼多的獨特索引 - 這部分很簡單。

現在假裝我希望能夠添加一個可以訪問所有租戶的全局用戶,但前提是電子郵件根本不存在於表中。另外,一旦記錄存在,沒有其他人 - 無論是否出租 - 都可以使用相同的電子郵件。

爲了清楚起見,全球用戶可能只是有一個空的租戶ID,但我們也可能會添加一個global布爾值。

有沒有辦法爲這個邏輯寫約束?您不能簡單地使電子郵件在全球範圍內受到限制,因爲它們無法在租戶之間重複使用,並且如果您使用空的租戶ID進行索引,則postgres將允許未安裝的用戶(如果租借的用戶具有相同的e -郵件。

我查看了排除約束和檢查,但無法弄清楚如何組合它們(如果tenant_id爲空,則唯一地限制全局電子郵件,並在插入時檢查具有空租戶ID和匹配電子郵件的記錄任何記錄)。

請不要問我爲什麼這樣做,讓 - 我的表是不實際的用戶和我們已經考慮並駁回其他架構:)

提前感謝!

+0

爲什麼不通過(電子郵件,租戶)的唯一索引? – McNets

+1

正如我所說的「他們的電子郵件是唯一索引給他們的租客的」 - 我們已經涵蓋了第一部分,這很容易。問題是關於第二部分。 – tekunokurato

回答

0

您可以使用一個唯一的約束兩個領域:

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, '[email protected]'), 
(2, 1, '[email protected]'); 

insert into myUsers values 
(3, 2, '[email protected]'); 

下一頁插入會引發錯誤:

insert into myUsers values 
(4, 2, '[email protected]'); 

Error(s), warning(s):

23505: duplicate key value violates unique constraint "myusers_email_tenant_key"

檢查在這裏:http://rextester.com/AJZVI34616

對於第二部分問題:

Now pretend that I want to be able to add a global user that can access all tenants, but only if the e-mail doesn't already exist in the table at all.

一個解決辦法是保留admin用戶的租戶:

tenant = 0 <-- admin users 

但獨特的約束允許重複的郵件,我建議你到rol字段添加到該表中,還是有管理的另一個表用戶爲此目的。

就我而言,我們使用兩個表格,並且都有一個rol字段。

+0

感謝您的回答,我應該更清楚地知道我們已經涵蓋了第一部分 - 這很容易。 回覆:第二部分,正如我所指出的那樣,表格實際上不是用戶,而我們考慮了另一種架構,這對我們的代碼來說是最乾淨的。只是想了解我提到的限制條件是否可行。 – tekunokurato

+1

*「有可能」(不是「我們可能」) – tekunokurato

1

按照PostgreSQL文檔,你可以創建unique partial index這將有效地同你的桌子上創造獨特的局部約束:

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

使用這種技術,你可以創建管理員和非2個獨立的唯一索引 - 用戶。