Ниже — несколько рабочих вариантов (в зависимости от версии MySQL). Идея общая: «оборачиваем» значение в запятые, находим первое вхождение ",X," и удаляем только его, а затем обрезаем лишние начальные/концевые запятые.
1) MySQL 8.0+ (регулярные выражения с параметром occurrence)
Если у вас MySQL 8+, можно воспользоваться REGEXP_REPLACE с указанием заменить только первое вхождение:
Пример (удалить число 123 из столбца list_col таблицы my_table):
UPDATE my_table
SET list_col = TRIM(BOTH ',' FROM
REGEXP_REPLACE(CONCAT(',', IFNULL(list_col, ''), ','), ',123,', ',', 1, 1)
)
WHERE FIND_IN_SET('123', list_col) > 0;
Пояснение:
- CONCAT(',', list_col, ',') гарантирует, что искомый элемент всегда окружён запятыми.
- REGEXP_REPLACE(..., ',123,', ',', 1, 1) заменяет только первое вхождение подстроки ",123," на одну запятую.
- TRIM удаляет возможные ведущие/замыкающие запятые.
Если число передаётся как параметр, используйте CONCAT для шаблона:
SET @id := '123';
UPDATE my_table
SET list_col = TRIM(BOTH ',' FROM
REGEXP_REPLACE(CONCAT(',', IFNULL(list_col, ''), ','), CONCAT(',', @id, ','), ',', 1, 1)
)
WHERE FIND_IN_SET(@id, list_col) > 0;
2) MySQL < 8.0 (без REGEXP_REPLACE) — с помощью INSTR, LEFT и SUBSTRING
Этот вариант работает в старых версиях:
SET @id := '123';
UPDATE my_table
SET list_col = TRIM(BOTH ',' FROM (
CASE
WHEN INSTR(CONCAT(',', IFNULL(list_col, ''), ','), CONCAT(',', @id, ',')) = 0
THEN IFNULL(list_col, '')
ELSE CONCAT(
LEFT(CONCAT(',', IFNULL(list_col, ''), ','), INSTR(CONCAT(',', IFNULL(list_col, ''), ','), CONCAT(',', @id, ',')) - 1),
SUBSTRING(
CONCAT(',', IFNULL(list_col, ''), ','),
INSTR(CONCAT(',', IFNULL(list_col, ''), ','), CONCAT(',', @id, ',')) + CHAR_LENGTH(CONCAT(',', @id, ','))
)
)
END
))
WHERE FIND_IN_SET(@id, list_col) > 0;
Пояснение:
- s := CONCAT(',', list_col, ',')
- pos := INSTR(s, CONCAT(',', id, ','))
- Если pos = 0 — ничего не делаем.
- Иначе составляем s_new = LEFT(s, pos-1) + SUBSTRING(s, pos + length(',id,')), — таким образом удаляется только первое вхождение.
- В конце TRIM удаляет лишние запятые.
Замечания и тонкости
- Эти способы работают корректно для списка чисел, разделённых запятыми (без пробелов). Если есть пробелы, можно предварительно удалить/нормализовать пробелы (REPLACE(list_col,' ','')) или подстроить шаблоны.
- Используйте WHERE FIND_IN_SET(@id, list_col) > 0 чтобы обновлять только нужные строки.
- Если ваши элементы могут содержать ведущие нули или прочие символы, убедитесь, что шаблон соответствует ожидаемому формату.
- Хранение списков через CSV в одном столбце не рекомендуется для масштабируемости и целостности данных; лучше нормализовать в отдельную таблицу. Но для быстрого «правильного удаления одного вхождения» приведённые варианты подойдут.
Если хотите — могу дать готовую процедуру/функцию, чтобы вызывать удаление по id и имени таблицы/столбца.