Таблица базы данных с обнуляемым внешним ключом - PullRequest
0 голосов
/ 21 марта 2019

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

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

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

1 Ответ

2 голосов
/ 21 марта 2019

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

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

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

Другой подход заключается в том, чтобы всегда устанавливать user_id (NOT NULL) и разрешать client_id необязательно.Если client_id НЕДЕЙСТВИТЕЛЕН, вы знаете - он обновляется пользователем.Если это не 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.Из-за дизайна (audit-trail -> app -> client -> user) и 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.Но пока это не важно, мне было бы все равно.

...