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 

У нас это очень покрыто уникальным индексом - эта часть проста.

Теперь притворите, что я хочу иметь возможность добавлять глобального пользователя, который может получить доступ ко всем арендаторам, но только в том случае, если электронное письмо еще не существует в таблице. Кроме того, как только запись будет существовать, никто другой, будь то арендатор или нет, сможет использовать одно и то же электронное письмо.

Для большей ясности глобальные пользователи могут просто иметь нулевой идентификатор арендатора, но мы, скорее всего, также добавим global boolean.

Есть ли способ написать ограничения для этой логики? Вы не можете просто сделать электронные письма глобально однозначно ограниченными, потому что они не смогут быть повторены между арендаторами, и если вы индексируете нулевой идентификатор арендатора, postgres разрешит незаслуженному пользователю, если есть арендаторы с одним и тем же e -mail.

Я рассмотрел ограничения и проверки исключений, но не смог понять, как их объединить (однозначно ограничить электронную почту глобально, если tenant_id имеет значение NULL, и проверить записи с нулевым идентификатором арендатора и сопоставление электронной почты при вставке любая запись).

Пожалуйста, не спрашивайте, почему я делаю вещи так - мой стол не на самом деле пользователи и мы рассматривали и освобождаемые другие архитектуры :)

Спасибо заранее!

+0

Почему не уникальный индекс (адрес электронной почты, арендатор)? – McNets

+1

Как я уже сказал, «их электронные письма однозначно индексируются их арендаторам» - у нас есть первая часть, это легко. вопрос касается второй части. – tekunokurato

ответ

0

Вы можете использовать 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, '[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.

Одним из решений может быть, чтобы зарезервировать арендатора для пользователей администратора:

tenant = 0 <-- admin users 

Но UNIQUE ограничение позволяет дублированные электронные письма, я рекомендую вам добавить rol поле в этой таблице, или иметь другую таблицу администратора пользователей для этой цели.

В моем случае мы используем две таблицы, и оба имеют поле rol.

+0

Спасибо за ответ, я должен был быть более ясным, что у нас уже есть первая часть - это легко. Re: вторая часть, так как я заметил, что таблица на самом деле не для пользователей, и хотя мы рассматривали альтернативные архитектуры, это было на сегодняшний день самым чистым для нашего кода. Просто хотел понять, возможно ли ограничение, о котором я говорил, мы можем. – tekunokurato

+1

* «возможны» (не «мы возможны») – tekunokurato

1

Согласно PostgreSQL документации вы можете создать unique partial index, который будет фактически то же самое, как создание уникального частичное ограничение на вашем столе:

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

Используя эту технику, вы можете создать 2 отдельные уникальные индексы для администратора и не -admin пользователей.

Смежные вопросы