Есть 3 таблицы: Пользователь , Вещь , Вещество .
Вещь может быть active
и inactive
.Один Пользователь может иметь много вещей, но только один может быть active
в то время.Когда вещь становится inactive
, она не может быть активирована снова.Пользователь может использовать active
Thing, что должно привести к созданию ThingUse с его собственным уникальным идентификатором использования.Я должен, вероятно, отметить, что в конечном итоге будут миллионы, если не миллиарды ThingUse *
Пример:
user1(id: 1)
создает thing_1(id: 1, owner: 1, active: true)
user1
использует thing_1
, что приводит к thing_use_1(id: 1, thingId: 1, useId: 1)
user1
использует thing_1
, что приводит к thing_use_2(id: 2, thingId: 1, useId: 2)
user1
создает thing_2(id: 2, owner: 1, active: true)
, теперь thing_1
должно стать thing_1(id: 1, owner: 1, active: false)
- , с этого момента
thing_1
неактивно и больше не может быть использовано / реактивировано user1
создает thing_use_3(id: 3, thingId: 2, useId: <strong>1</strong>)
<- уведомление <code>useId был установлен на 1 user1
создает thing_use_4(id: 4, thingId: 2, useId: 2)
user2(id: 2)
создает thing_3(id: 3, owner: 2, active: true)
user2
создает thing_use_5(id: 5, thingId: 3, useId: <strong>1</strong>)
<- уведомление <code>useId было установлено на 1
На этом этапе БД должна выглядеть следующим образом:
user_1(id: 1)
thing_1(id: 1, owner: 1, active: false)
thing_use_1(id: 1, thingId: 1, useId: 1)
thing_use_2(id: 2, thingId: 1, useId: 2)
thing_2(id: 2, owner: 1, active: true)
thing_use_3(id: 3, thingId: 2, useId: 1)
thing_use_4(id: 4, thingId: 2, useId: 2)
user_2(id: 2)
thing_3(id: 3, owner: 2, active: true)
thing_use_5(id: 5, thingId: 3, useId: 1)
Другие примечания:
- Каждое ThingUse в пределах одного Thing должно иметь уникальный (с автоматическим приращением) useId.
- Если это не было очевидно из приведенного вышепример отношений между User to Thing и Thing до ThingUse - это один ко многим.
Таким образом, в основном есть 2 проблемы:
Проблема A:
Одиночный Пользователь может иметь только 1 active
Вещь в данный момент.Из того, что я прочитал, в MySQL невозможно создать специальную логическую строку, которая допускает один TRUE
и несколько FALSES
.Однако я придумал 2 «обходных пути».Они оба кажутся немного странными, хотя, возможно, есть лучшие решения:
- Создать
uniqueIndex(owner, active)
на Вещь и использовать true
/ null
как active
/inactive
флагов, поскольку MySQL не рассматривает пустые значения как дублированные значения. - Вторая идея состоит в том, чтобы рассматривать самого последнего пользователя Thing как
active
.Проблема в этом случае заключается в том, что это не на 100% прямолинейно по отношению к происходящему + Я предполагаю, что будет сложно / медленно писать запросы типа find all active things across all users
. - (добавлено в @ Edit1) Третья идея - удалить столбец
active
из Thing и добавить столбец activeThingId
в таблицу User .Таким образом, для одного пользователя будет невозможно иметь несколько активных вещей одновременно, и будет легко запрашивать «все активные вещи».
Проблема B:
Один Thing не может иметь несколько ThingUse с одним и тем же идентификатором использования.Для этого я могу установить uniqueIndex(thingId, useId)
на ThingUse .Это предотвратит случайное использование дубликатов.Однако все еще существует проблема с получением правильного следующего идентификатора использования / установки.Я мог бы технически закодировать эту логику на уровне приложения, но я бы предпочел, чтобы БД обрабатывал ее для меня, если это возможно.
(добавлено @ Edit2 )
Спасибо, @JairSnow, мне удалось частично решить проблему B , используя триггер, основанный на вашей процедуре:
CREATE TRIGGER triggerName
BEFORE INSERT ON ThingUse
FOR EACH ROW BEGIN
SET @actual_value = (SELECT COUNT(*) FROM ThingUse WHERE thingId=NEW.thingId);
IF (@actual_value IS NULL) THEN
SET @actual_value = 0;
END IF;
SET NEW.useId=@actual_value;
END
Однако мне пришлось использовать COUNT(*)
вместо MAX(useId)
, потому что по какой-то причинес последним я получал дубликат useId
.
Единственная проблема сейчас заключается в том, что если я добавлю ThingUse
быстро ex.не дожидаясь завершения других / предыдущих запросов, я получаю страшную тупиковую ошибку: ER_LOCK_DEADLOCK: Deadlock found when trying to get lock; try restarting transaction
.
@ Edit1 : добавлено A.3.
@Edit2 : частично решено Проблема B .