Результат может быть возвращен MySQL-запросом без сценария.
SELECT CONCAT(LPAD(r.lo,4,'0'),'-',LPAD(r.hi,4,'0')) AS gap
, r.lo
, r.hi
-- , d.minval IS NULL AS gap
-- , d.*
FROM (SELECT rl.lo, rh.hi
FROM (SELECT 0000 AS lo UNION
SELECT rlo.maxval+1
FROM example1 rlo
WHERE rlo.maxval < 9999
) rl
JOIN (SELECT 9999 AS hi UNION
SELECT rhi.minval-1
FROM example1 rhi
WHERE rhi.minval > 0000
) rh
ON rh.hi >= rl.lo
GROUP BY rl.lo, rh.hi
) r
LEFT
JOIN example1 d
ON r.lo BETWEEN d.minval+0 AND d.maxval+0
OR r.hi BETWEEN d.minval+0 AND d.maxval+0
OR d.minval+0 BETWEEN r.lo AND r.hi
OR d.maxval+0 BETWEEN r.lo AND r.hi
WHERE d.minval IS NULL
ORDER
BY r.lo, r.hi
-- , d.minval, d.maxval
Подход, который я использовал, состоял в том, чтобы начать с набора всех возможных разрывов. Мы знаем, что каждый потенциальный разрыв будет:
- старт на
0000
или любой maxval+1
- конца в
9999
или любой minval-1
Итак, мы можем создать список всех возможных «начала разрыва» и список всех возможных «пробелов». (Я думал об этом как о «диапазонах», когда писал запрос. Я использовал псевдонимы для встроенных просмотров, r
для «range», rh
для «высокого» конца диапазона и rl
для «низкого» конца диапазон
Введенный псевдоним «r
» возвращает все возможные строки, которые могут быть пробелом. (Это почти крест-соединение, но мы исключаем строки, где r.hi будет меньше, чем r.lo. I подумайте, что фактический термин, который используется для этого, - это «объединение неравенства».)
Образец антисоединения назад к исходной таблице диапазонов исключает строки, которые не являются реальными пробелами, поскольку существует некоторое совпадение с одним из диапазонов в таблицу. (Шаблон антисоединения - ЛЕВЫЙ ПРИСОЕДИНЕНИЕ, а затем предикат в предложении WHERE для исключения строк был результатом операции LEFT JOIN, и мы оставили строки, которые не имели соответствия. В качестве альтернативы, такое же устранение может быть выполнено с использованием подхода NOT EXISTS (correlated subquery)
.)
(Этот запрос будет также возвращать разрыв 0000-9999
, когда нет ни одной строки в таблице диапазонов.)
Для тестовой установки случае (я настроил OP 0000
значения 0055
, чтобы продемонстрировать, что это будет идентифицировать пробел, который начинается 0000
.)
CREATE TABLE `example1` (minval INT(4), maxval INT(4));
INSERT INTO `example1` VALUES (0055,1000),(1500,8999),(0100,0200),(5000,6999);
gap lo hi
--------- ----- -----
0000-0054 0 54
1001-1499 1001 1499
9000-9999 9000 9999
EDIT
Я просто заметил, что О.П. комментарий о том, что да tatype - CHAR (4), я предположил, что это целочисленный тип, вероятно, INT(4) ZEROFILL
. В приведенном выше запросе также будут работать типы CHAR, но мы должны убедиться, что CHAR преобразуется в целое число, а самый простой способ сделать это - добавить «+ 0» к ссылкам столбца, эта настройка выполняется и протестирована.
CREATE TABLE `example1` (minval CHAR(4), maxval CHAR(4));
INSERT INTO `example1` VALUES ('0055','1000')
,('1500','8999'),('0100','0200'),('5000','6999');
Что такое тип данных для min и max varchar? Почему бы не int? Почему есть ведущие нули? – user4035
Datatype is char (4) – Chinaski
Почему вы храните целые значения в столбцах char? – user4035