Reputation: 1230
Example:
Here is the employee table:
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`),
);
The code
is a simple login code of 4 characters. Soft delete is implemented using deleted_at
field. Current employees are those with deleted_at=NULL
.
We need to keep the code unique between the current employees.
Using a UNIQUE Constraints on the code
field will prevent current employees from using codes that have been used by a soft-deleted employee.
How to enforce this constraint?
This is an example of the general problem of how to enforce consistency constraints in MySQL.
Edit:
The schema could be changed to make use of unique constraints as @bill-karwin suggests.
What about applying complex consistency constraints that may span multiple tables?
Upvotes: 0
Views: 793
Reputation: 562328
One solution is to create a nullable column is_active
that is restricted to either NULL or a single non-NULL value. The columns code
and is_active
together must be unique.
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`)
);
If is_active
is NULL, then it allows any number of duplicates in the code
column. If is_active
is not NULL, then it allows only one value 'yes' and therefore each value in the code
column must be unique.
deleted_at
no longer indicates if the employee is currently active or not, only when then were inactivated.
Re your comment:
Constraints that span multiple tables are called ASSERTIONS
in the SQL standard, but there is literally no RDBMS product that implements that feature from the standard.
Some implement constraints with triggers, but it's not always obvious how to design triggers to do what you want efficiently.
Honestly, most people resort to application logic for these sorts of constraints. This comes with some risk of race conditions. As soon as you do a SELECT statement to verify the data satisfies the constraints, some other concurrent session may commit data that spoils the constraint before your session can commit its changes.
The only solution is to use pessimistic locking to ensure no other session can jump ahead of you.
Upvotes: 0
Reputation: 147166
One relatively simple solution to your problem would be to change the deleted_at
column to default to something other than NULL
(e.g. '1900-01-01', or even the "zero" date '0000-00-00' if you have them enabled). You can then create a UNIQUE
index on (code, deleted_at)
which would prevent any employee from using a code which a current employee had (since you would get a match on (code,default)
), but not exclude them using a code which a previous employee had used, since the default value would not match the deleted_at
timestamp.
Upvotes: 1