Maxi2002
@Maxi2002
Начинающий Айтишник

Как выбрать записи по всем возможным комбинациям списка?

Есть поле в таблице, представляющее собой строковый список чисел через запятую, с переменным количеством значений и разным порядком чисел. Например:
Строка 1: 111
Строка 2: 222, 333
Строка 3: 333, 222
Строка 4: 333, 111, 222
Можно ли средствами SQL выбрать записи, подходящие под все возможные сочетания указанного списка?
Т.е. например сделать одним запросом:
SELECT * FROM table WHERE field = '222,333'
SELECT * FROM table WHERE field = '333, 222'

Вариант с IN не подходит, т.к. список комбинаций не известен заранее. На входе только одна исходная комбинация 222,333 например
  • Вопрос задан
  • 181 просмотр
Пригласить эксперта
Ответы на вопрос 2
trapwalker
@trapwalker
Программист, энтузиаст
Никогда плотно не работал с MySQL. Быстренько погуглил и, вроде как, тривиально оно не делается. В постгресе, кстати, такое провернуть легко. Там можно сплитнуть строку, превратить ее в массив, потом развернуть его в таблицу и сджойнить.
Вам же я бы посоветовал два варианта:
1) нормализовать вашу таблицу внешними средствами: написать скрипт на чем умеете и сделать таблицу фрагментов со ссылкой на исходную запись. Тогда вопрос решается тривиально.
2) внешним скриптом проапдейтить вашу таблицу отсортировав числа, пропсианные через запятую. Это даст возможность однозначно проверять на совпадение строк без вариативности.
3) генерить SQL собирая через UNION все варианты сочетаний - это жутко неэффективно, а количество сочетаний растёт очень быстро с ростом количества компонентов строки.
4) фильтровать не на уровне SQL, а, к примеру питоновским скриптиком снаружи - этот вариант не решаение вашего вопроса, но в некоторых случаях как быстрая мера вполне подошел бы.
Ответ написан
Комментировать
@MaximaXXl
Если надо просто найти можно find_in set
with t1 as (select 1 id, '222' se union all
select 2, '222,333' union all
select 3, '333,222' union all
select 4, '333,111,222')

select *
from t1
where find_in_set( '222', se) and find_in_set( '333', se)


Если надо чтоб стояли именно рядом
with t1 as (select 1 id, '222' se union all
select 2, '222,333' union all
select 3, '333,222' union all
select 4, '333,111,222')

select *
from t1
where find_in_set( '222', se) and find_in_set( '333', se)
having abs(find_in_set( '222', se)-find_in_set( '333', se)) = 1
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы