Обходное решение для выполнения «INSERT … ON DUPLICATE KEY UPDATE» с нулевым значением для уникального ключа

Во-первых, вот моя структура кода и чего я хочу достичь:

У меня эти 3 таблицы:

+----------------------+ | CONFIG_CAMPAIGN | +----------------------+ | - id_config | | // other fields | +----------------------+ +----------------------+ | SLOT_CONFIG | +----------------------+ | - id_slot_config | | - id_config | | - id_slot_pb | +----------------------+ +----------------------+ | SLOT_PLACE_BOX | +----------------------+ | - id_slot_pb | | - id_place_box | | - date | | - hour | | - slot_available | +----------------------+ 

Таким образом, один «slot_place_box» может иметь несколько «config» и один «config» может быть на нескольких «slot_place_box». У меня есть триггер на «slot_config», чтобы обновить поле «slot_available» в соответствии с конфигурацией.

Теперь у меня есть PHP, где я получаю некоторые данные FORM и создаю SQL-запрос, который выглядит так (когда у меня есть моя проблема):

 INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-10', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box; SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-10' AND SPB.hour IS NULL); INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id); INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-11', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box; SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-11' AND SPB.hour IS NULL); INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id); INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-12', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box; SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-12' AND SPB.hour IS NULL); INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id); // and so on 

Идея состоит в том, чтобы создать новый «slot_place_box» + «slot_config», если у меня нет дубликата в соответствии с новой конфигурацией, которую я создаю ранее в своем коде

ИЛИ

Если у меня уже есть «slot_place_box» с тем же «id_place_box + date + hour», то я только вставляю новый «slot_config» с идентификатором new_config + «slot_place_box», который у меня уже есть.

Я выбираю «INSERT … ON DUPLICATE KEY / do nothing /», потому что мне нужен идентификатор строки I INSERT / у меня уже есть.

У меня есть UNIQUE индексный ключ в «slot_place_box» для полей «id_place_box + date + hour». Моя проблема начинается, потому что «час» может составлять час (например, «12:00:00»), но также может быть NULL (= для меня, когда NULL означает «весь день» «даты»). Когда час равен NULL, мой индекс UNIQUE не работает, поэтому INSERT происходит, и у меня есть дубликат в базе данных.

Итак, как я могу сделать это «INSERT … ON DUPLICATE KEY UPDATE» работает с индексом UNIQUE со значением NULL?

Я не могу использовать это решение ( здесь ), потому что я использую MySQl 5.6, поэтому я попытаюсь сделать триггер, как кто-то предложил мне в моем последнем вопросе ( здесь ).

Я новичок в SQL, поэтому мне нужна помощь, чтобы достичь этого триггера . Идея, если я хорошо понимаю, состоит в том, чтобы создать некоторый «виртуальный» столбец с триггером и добавить в него некоторое значение, если «час» равен нулю + добавить этот виртуальный столбец в мой индекс UNIQUE, чтобы он работал в режиме DUPLICATE KEY.

Поэтому мои вопросы:

  • Как я могу создать этот «виртуальный столбец» в триггере?
  • Как я могу использовать этот «виртуальный столбец» для моего индекса UNIQUE, если мне нужно значение «час», когда оно не является NULL?
  • У вас есть идея?

Я отвечу сам, но если у вас есть другие решения, мне все равно интересно это услышать. Это решение работает для меня, потому что я работаю над новым проектом, поэтому он не влияет на код, который я уже написал.

Чтобы обойти эту проблему, я добавляю новый столбец в таблицу «slot_place_box»:

 +----------------------+ | SLOT_PLACE_BOX | +----------------------+ | - id_slot_pb | | - id_place_box | | - date | | - hour | | - slot_available | | - virtual_hour | <- new field +----------------------+ 

Это новое поле – VARCHAR (10), равное «час», если не NULL (например: «12:00:00») или равно «1» по умолчанию, или когда «час» равен NULL.

Затем я изменяю свой индекс UNIQUE в этой таблице для «id_place_box + date + virtual_hour», поэтому я никогда не получу значение NULL. Затем я ОБНОВЛЯЮТ данные, которые у меня уже есть в моей таблице:

 UPDATE slot_place_box SET (virtual_hour = IF(hour is NULL, '1', hour); // Without the safe UPDATE (I use MySQL WorkBench) 

Я изменяю свой цикл PHP для создания моего запроса с новым столбцом:

  foreach($SPB_data_array as $index => $SPB_data) { $current_id_pb = $SPB_data['id_pb']; $current_date = $SPB_data['date']; if (!empty($SPB_data['hour'])) { $current_hour = $SPB_data['hour']; $sql_slot_pb .= 'INSERT INTO media.slot_place_box (id_place_box, date, hour, virtual_hour) VALUES ('. $current_id_pb .', \''. $current_date .'\', \''. $current_hour .'\', \''. $current_hour .'\') ON DUPLICATE KEY UPDATE id_place_box=id_place_box; SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = '. $current_id_pb .' AND SPB.date = \''. $current_date .'\' AND SPB.hour = \''. $current_hour .'\'); INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (:new_config_id, @id); '; } else { $sql_slot_pb .= 'INSERT INTO media.slot_place_box (id_place_box, date, hour) VALUES ('. $current_id_pb .', \''. $current_date .'\', NULL) ON DUPLICATE KEY UPDATE id_place_box=id_place_box; SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = '. $current_id_pb .' AND SPB.date = \''. $current_date .'\' AND SPB.hour IS NULL); INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (:new_config_id, @id); '; } } 

Я просто добавил четвертый столбец со значением «час», когда «час» не равен NULL, по умолчанию «virtual_hour» – «1», поэтому нет необходимости добавлять его в этом случае.

Я не знаю, является ли это лучшим решением для проекта BIG с большим количеством данных, но в моем случае это был самый простой способ решить мою проблему.