mysql – INSERT диапазон дат в столбцы даты IF IF не перекрываются с существующими

У меня есть следующая структура таблицы:

Имя таблицы: avail

id (autoincremetn) | acc_id | start_date | end_date ------------------------------------------------------- 1 | 175 | 2015-05-26 | 2015-05-31 | ------------------------------------------------------- 2 | 175 | 2015-07-01 | 2015-07-07 | ------------------------------------------------------- 

Он используется для определения доступности диапазона дат, например. все даты между start_date и end_date недоступны для данного acc_id.

Основываясь на пользовательском вводе, я закрываю разные диапазоны, но я хотел бы сделать ошибку, если пользователь пытается закрыть (отправить) диапазон, который имеет его начало ИЛИ end_date где-то в диапазоне уже существующего (для отправленного acc_id) в БД. В этом примере start_date: 2015-05-30 end_date: 2015-06-04 будет хорошим кандидатом.

Я нашел этот QA: MySQL перекрывает даты, не конфликтует

что в значительной степени объясняет, как это сделать в 2 этапа, 2 запроса с некоторой логикой PHP между ними.

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

EDIT :

В ответ на комментарий Петра я уточню дальнейшую проверку:

следует избегать любых перекрытий, даже если они охватывают весь диапазон или находятся внутри существующего диапазона. Кроме того, если начальные или конечные даты совпадают с существующими датами начала или окончания, это должно рассматриваться как перекрытие. Иногда некоторые acc_id уже имеют более одного звонка в таблице, поэтому валидация должна быть выполнена против всех записей с данным acc_id.

Рассмотрим следующее …

 DROP TABLE IF EXISTS avail; CREATE TABLE avail (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,acc_id INT NOT NULL ,start_date DATE NOT NULL ,end_date DATE NOT NULL ); INSERT INTO avail VALUES (1,175,'2015-05-26','2015-05-31'), (2,175,'2015-07-01','2015-07-07'); SELECT * FROM avail; +----+--------+------------+------------+ | id | acc_id | start_date | end_date | +----+--------+------------+------------+ | 1 | 175 | 2015-05-26 | 2015-05-31 | | 2 | 175 | 2015-07-01 | 2015-07-07 | +----+--------+------------+------------+ INSERT INTO avail (acc_id,start_date,end_date) SELECT 176,'2015-06-01','2015-06-05' FROM (SELECT 1) x -- was FROM avail LEFT JOIN avail y ON y.start_date < '2015-06-05' AND y.end_date > '2015-06-01' WHERE y.id IS NULL LIMIT 1; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 SELECT * FROM avail; +----+--------+------------+------------+ | id | acc_id | start_date | end_date | +----+--------+------------+------------+ | 1 | 175 | 2015-05-26 | 2015-05-31 | | 2 | 175 | 2015-07-01 | 2015-07-07 | | 3 | 176 | 2015-06-01 | 2015-06-05 | +----+--------+------------+------------+ INSERT INTO avail (acc_id,start_date,end_date) SELECT 176,'2015-06-01','2015-06-05' FROM avail LEFT JOIN avail y ON y.start_date < '2015-06-05' AND y.end_date > '2015-06-01' WHERE y.id IS NULL LIMIT 1; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 SELECT * FROM avail; +----+--------+------------+------------+ | id | acc_id | start_date | end_date | +----+--------+------------+------------+ | 1 | 175 | 2015-05-26 | 2015-05-31 | | 2 | 175 | 2015-07-01 | 2015-07-07 | | 3 | 176 | 2015-06-01 | 2015-06-05 | +----+--------+------------+------------+ 

К сожалению, использование MySQL просто невозможно. Или, по крайней мере, практически. Предпочтительным способом было бы использовать ограничения SQL CHECK, они находятся в стандарте языка SQL. Однако MySQL их не поддерживает.

См. https://dev.mysql.com/doc/refman/5.7/en/create-table.html.

Предложение CHECK анализируется, но игнорируется всеми механизмами хранения.

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

В MySQL для решения этой проблемы может использоваться триггер, который будет проверять перекрывающиеся строки перед вставкой / обновлением и вызывать ошибку с помощью инструкции SIGNAL . (См. https://dev.mysql.com/doc/refman/5.7/en/signal.html ). Однако для использования этого решения вам придется использовать последнюю версию MySQL.

Помимо чистых SQL-решений, это обычно выполняется в логике приложения, поэтому в зависимости от того, какая программа обращается к базе данных MySQL, она обычно проверяет эти ограничения, запрашивая каждую строку, которая нарушена новой записью в SELECT COUNT(id) ... заявление. Если возвращаемый счетчик больше 0, он просто не вставляет / обновляет.