MySQL: как реализовать ограничения согласованности? - PullRequest
0 голосов
/ 18 сентября 2018

Пример:

Вот таблица сотрудников:

CREATE TABLE `employees` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `code` varchar(4) NOT NULL,
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
);

code - это простой код входа из 4 символов. Мягкое удаление реализовано с использованием поля deleted_at. Нынешние сотрудники - это те, у кого deleted_at=NULL.

Нам необходимо сохранить уникальный код для текущих сотрудников.

Использование УНИКАЛЬНЫХ Ограничений в поле code не позволит текущим сотрудникам использовать коды, которые использовались мягко удаленным сотрудником.

Как применить это ограничение?

Это пример общей проблемы применения ограничений согласованности в MySQL.

Edit:

Схема может быть изменена для использования уникальных ограничений, как предлагает @ bill-karwin.

Как насчет применения сложных ограничений согласованности, которые могут охватывать несколько таблиц?

  • Один из способов (если это возможно) - изменить схему, чтобы применить ограничения с использованием ограничения внешнего ключа или ограничения уникальности.
  • Есть ли другой способ применения сложных ограничений согласованности?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Одним из решений является создание пустого столбца is_active, который ограничен значением NULL или одним значением, отличным от NULL.Столбцы code и is_active вместе должны быть уникальными.

CREATE TABLE `employees` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `code` varchar(4) NOT NULL,
  `is_active` enum('yes'),
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY (`code`, `is_active`)
);

Если is_active равно NULL, то в столбце code допускается любое количество дубликатов.Если is_active не равно NULL, тогда допускается только одно значение «да», и поэтому каждое значение в столбце code должно быть уникальным.

deleted_at больше не указывает, является ли данный сотрудник активным в данный момент илинет, только , когда тогда были инактивированы.


Ваш комментарий:

Ограничения, охватывающие несколько таблиц, называются ASSERTIONS в стандарте SQL, нобуквально не является продуктом СУБД, который реализует эту функцию из стандарта.

Некоторые реализуют ограничения с помощью триггеров, но не всегда очевидно, как спроектировать триггеры, чтобы делать то, что вы хотите эффективно.

Честно говоря, большинстволюди прибегают к логике приложения для такого рода ограничений.Это идет с некоторым риском условий гонки.Как только вы выполните инструкцию SELECT, чтобы проверить, что данные удовлетворяют ограничениям, какой-то другой параллельный сеанс может зафиксировать данные, которые портят ограничение, прежде чем ваш сеанс сможет зафиксировать его изменения.

Единственное решение - использовать пессимистическую блокировку дляубедитесь, что никакая другая сессия не может опередить вас.

0 голосов
/ 18 сентября 2018

Одним из относительно простых решений вашей проблемы было бы изменить столбец deleted_at на значение по умолчанию, отличное от NULL (например, «1900-01-01» или даже «нулевая» дата) 0000-00- 00 ', если они у вас включены). Затем вы можете создать индекс UNIQUE для (code, deleted_at), который запретил бы любому сотруднику использовать код, который был у текущего сотрудника (поскольку вы получите совпадение для (code,default)), но не исключил их, используя код, который предыдущий сотрудник использовал, поскольку значение по умолчанию не будет соответствовать отметке времени deleted_at.

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