Таблица SQL с ограничением на несколько NULL - PullRequest
2 голосов
/ 23 июня 2019

Я использую MYSQL и у меня есть таблица устройств.Каждое устройство имеет, среди прочего, идентификатор, называемый mac_address (это не ПК), и столбец с именем deleted_date.

Если устройство не является активным,его deleted_date равно отметке времени, и тогда должно быть нормально добавить новое устройство с таким же mac_address.Если он активен, его deleted_date равен NULL, и тогда не следует добавлять новое устройство с таким же mac_address.

. Я обнаружил, что возможно иметь два устройства, которые все еще работают.активен с тем же mac_address, что неправильно.После некоторых исследований я понял, что не могу сравнить NULL с NULL, поскольку он не считается одним и тем же значением.

Буду признателен за идею, как обойти это.

  • Два устройства с одинаковыми mac_address и deleted_date имеют значение NULL: НЕПРАВИЛЬНО
  • Два устройства с одинаковым mac_address, одно deleted_date равно NULL, а другоеимеет значение: OK
  • Два устройства с одинаковыми mac_address, и deleted_date имеет значение для обоих: OK

В данный момент это важная часть создания таблицы и ограничения:

'CREATE TABLE `iot_devices` (
  `pk` int(11) NOT NULL AUTO_INCREMENT,
  `device_id` int(11) DEFAULT NULL,
  `device_name` varchar(100) NOT NULL,
  `delete_date` timestamp NULL DEFAULT NULL,
  `mac_address` varchar(12) DEFAULT NULL,
  PRIMARY KEY (`pk`),
  UNIQUE KEY `idx_device_id` (`device_id`),
  UNIQUE KEY `idx_mac_address_delete_date` (`mac_address`,`delete_date`),
)

Ответы [ 3 ]

2 голосов
/ 23 июня 2019

Вы не можете сделать это только с помощью оператора INSERT, но вы можете, например, с помощью триггера.

drop trigger if exists t;
delimiter $$

create trigger t before insert on t
for each row
begin
        declare vcount int default 0;
        select ifnull(count(*),0) into vcount from t where mac_address = new.mac_address and delete_date is null; 
       if vcount <> 0 then
            SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'An error occurred';
        end if;
end $$
delimiter ;

Обратите внимание, что вам, вероятно, придется сделать что-то подобное в ОБНОВЛЕНИИ.

1 голос
/ 23 июня 2019

Нам нужно будет выявить и решить следующее:

  • какие возможные проблемы у нас уже могут быть
  • как обрабатывать вставку
  • какобработать обновление

Возможная проблема

У вас может быть несколько записей с одинаковыми mac_address и null delete_date.Вам нужно будет убедиться, что у вас есть по одной записи для каждого mac_address, который имеет null delete_date.Если вы хотите использовать constraint для unique, вы можете установить не удаленные записи 'delete_date на какую-то дату в очень отдаленном будущем и будете знать, что записи, имеющие delete_date в будущем, не будут удалены,Если эта будущая дата будет постоянной, то это решит вашу проблему, но это решение не очень элегантно.Вместо этого я все равно использовал бы дату null, но тогда вам потребуются другие меры.

Триггеры перед вставкой или обновлением

Ответ P.Salmon описывает такой подход, я не буду его дублировать,но вместо этого проголосуйте за его ответ.Проблема с триггерами заключается в том, что в случае, когда есть еще записи, которые нужно вставить / обновить, и триггер выдает ошибку на раннем этапе, тогда некоторые допустимые вставки или модификации не произойдут.

Проблемы с вставкой и обновлением

Проблема с insert заключается в том, что новая запись будет соответствовать mac_address с null delete_date.Проблема с обновлением состоит в том, что обновленная запись будет приводить к дублированию mac_address с другой записью, которая имеет null delete_date.Вы можете сделать вставку select или update с условием, например:

where not ((not (iot_devices.deleted_date is null)) and (iot_devices.mac_address = 'youvalue'))

Обработка старых записей по мере продвижения

Вы можете обновить delete_date более старых записей кактриггер на insert или update

'' вместо нуля

Вы можете изменить тип вашего delete_date на varchar и иметь '' для не удаленных значений,Тогда вы можете использовать ограничение.Однако в этом случае поиск по delete_date станет более сложным.

0 голосов
/ 23 июня 2019

Вы правы, NULL нельзя сравнить с NULL

, но вы можете сравнить '' с '', поэтому

Используйте '' пустая строка не NULL в качестве значения по умолчанию

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...