Таблица базы данных с нулевым внешним ключом

Я создаю новый дизайн базы данных для своего сайта. В моей базе есть два типа пользователей. Итак, у меня есть user_t, и он связан с client_t. У одного пользователя может быть несколько клиентов. Теперь у меня есть app_t. Один клиент может иметь более одного приложения.

Это app_t может обновляться как клиентом, так и пользователем. Я создаю контрольную пробную таблицу для app_t, где я не хочу хранить имя в updated_by, потому что оно может измениться. Вместо этого я хочу иметь столбцы client_id и user_id. В этом случае, когда клиент обновляет таблицу, столбец user_id будет нулевым, а когда пользователь обновляет таблицу client_id, будет нулевым. Оба этих идентификатора являются внешними ключами, которые ссылаются на столбцы первичного ключа соответствующих таблиц. Можно ли иметь такие нулевые значения?

Заранее спасибо.


person SBM    schedule 21.03.2019    source источник
comment
можно ли удалить пользователя или клиента?   -  person Paul Spiegel    schedule 21.03.2019
comment
@PaulSpiegel Нет, мы никогда не удаляем   -  person SBM    schedule 29.03.2019


Ответы (1)


Можно ли иметь такие нулевые значения?

Это субъективно. Вопрос: можно ли с ним работать? Возможно - да. Но может ли это гарантировать целостность? Нет.

Так что же может пойти не так? Вы можете установить оба внешних ключа или оставить оба NULL - и БД не будет жаловаться. В любом случае вы не знаете, кто обновил элемент.

Другой подход состоит в том, чтобы всегда устанавливать user_id (НЕ NULL) и позволять client_id быть необязательным. Если client_id равен NULL, вы знаете, что он обновляется пользователем. Если это не NULL, то вы знаете - он обновляется клиентом.

Затем вы можете получить имя с помощью:

select at.*, coalesce(c.name, u.name) as updated_by
from app_audit at
join user_t u        on u.id = at.user_id
left join client_t c on c.id = at.client_id

Но все еще может пойти не так. Вы можете сохранить идентификатор клиента, который не является «владельцем» приложения. То же самое относится и к user_id. Из-за конструкции (журнал аудита -> приложение -> клиент -> пользователь) и client_id, и user_id функционально зависят от app_id. Так что на самом деле все, что вам нужно, это app_id в качестве внешнего ключа и логический флаг, который сообщает вам, обновлен ли он пользователем или клиентом. Затем вы должны получить данные с помощью:

select at.*, coalesce(u.name, c.name) as updated_by
from app_audit at
join app_t a       on a.id = at.app_id
join client_t c    on c.id = a.client_id
left join user_t u on u.id = c.user_id  and a.updatet_by_user = 1

По поводу вашего комментария:

Я не верю в такие вещи, как «лучший подход» или «лучшая практика», когда проблема «достаточно сложна». Тогда возникает вопрос: лучше для чего? Обычно у вас есть несколько целей, таких как четкость, простота, удобство использования, гибкость, надежность. , производительность и, возможно, что-то еще. «Лучший подход» к гибкости может оказаться кошмаром для производительности, и наоборот.

Более широко используется термин "рекомендуемая практика". И нормализация базы данных считается хорошей практикой. Добавление user_id и client_id вводит функциональные зависимости от не ключа-кандидата, что нарушает 3NF.

С другой стороны, без этих столбцов вам понадобится еще одно JOIN в ваших запросах SELECT. Но пока это не существенно, мне было бы все равно.

person Paul Spiegel    schedule 21.03.2019
comment
Спасибо за ответ @PaulSpiegel. Извините за задержку с ответом. У нас была такая же идея иметь только ассоциацию app_id, а затем иметь флаг, обозначающий, является ли это клиентом или пользователем. Но мы не были уверены, является ли это лучшей практикой, потому что мы плохо знакомы с проектированием баз данных. Если вы действительно чувствуете, что это лучший подход, я продолжу и отмечу его как ответ. - person SBM; 29.03.2019
comment
@sureshbabu Мой ответ был слишком длинным для комментария, поэтому я обновил ответ. - person Paul Spiegel; 29.03.2019
comment
Не могли бы вы помочь с этим stackoverflow.com/questions/55501603/ - person SBM; 03.04.2019
comment
Если это не гарантирует целостность, зачем объявлять FK?? - person Rick James; 10.04.2019