Я бы по-прежнему предлагал преобразовать значение, разделенное запятыми, в строки. Управление этими столбцами CSV на обоих концах запроса является утомительным, подверженным ошибкам и неэффективным. При такой настройке вы не сможете использовать индексы.
С другой стороны, рассмотрим:
- таблицы поиска, в которых каждая запись хранит идентификатор пользователя и (одну) связанную службу
- таблица исключений, где каждая запись представляет службу для удаления
В большом наборе данных сканирование индекса происходит на порядок быстрее, чем полное сканирование: при наличии соответствующего индекса требуется всего 25 сравнений, чтобы найти соответствующую запись из 10 миллионов строк (log2 из 10 M равен 23,5).
Это также позволит вам упростить ваш запрос как:
SELECT l.*
FROM lookup_table l
LEFT JOIN exclusion_table e ON e.service = l.service
WHERE e.service IS NULL
Или:
SELECT l.*
FROM lookup_table l
WHERE NOT EXISTS (
SELECT 1 FROM exclusion_table e WHERE e.service = l.service
)
Если требуется агрегирование для каждого пользователя, оно может быть обработано с использованием функции SQL (или еще лучше на уровне представления).
Совет: вот запрос, который вы можете использовать для инициализации вашей новой таблицы; он разбивает столбец CSV на новые строки:
select distinct usr, trim(regexp_substr(serv, '[^,]+', 1, level)) serv
from (SELECT usr, services serv FROM user_services) t
connect by instr(serv, ',', 1, level - 1) > 0
См. это дБ <> скрипка
with user_services as (
select 'Rick' usr, '1,3,2,66,19' services from dual
union select 'Jerry', '1,2,19' from dual
)
select distinct usr, trim(regexp_substr(serv, '[^,]+', 1, level)) serv
from (SELECT usr, services serv FROM user_services) t
connect by instr(serv, ',', 1, level - 1) > 0
order by 1,2
USR | SERV
:---- | :---
Jerry | 1<br>
Jerry | 19<br>
Jerry | 2<br>
Rick | 1<br>
Rick | 19<br>
Rick | 2<br>
Rick | 3<br>
Rick | 66<br>