Первый способ. Декларативный.
Состоит в том чтобы объявить переменные для максимального количества значений. Поскольку он очевиден, то думаю что подробнее на этом способе останавливаться не стоит.
SELECT * FROM TABLE1
WHERE FK_ID IN (:IN_P1, :IN_P2, :IN_P3, :IN_P4, :IN_P5);
Второй способ. Рекурсивный.
Реализуется с помощью иерархических (читай рекурсивных) запросов Oracle. Для реализации этого способа нам понадобятся функции INSTR и SUBSTR и, собственно иерархический запрос.
INSTR - функция возвращает позицию подстроки внутри строкиЗапрос принимает входящий параметр - строку со значениями разделенными запятой (или любым другим подходящим символом) и превращает его во вьюху состоящую из значений входящей строки. Из этой вьюхи берутся данные для оператора IN.
REGEXP_SUBSTR - возвращает подстроку соответствующую регулярному выражению. Функция regexp_substr появилась только в десятой версии оракла, в предыдущих нужно шаманить с функциями SUBSTR и INSTR.
Что такое иерархические запросы можно прочитать на хабре (на русском) и в документации (на английском)
На практике это может выглядеть так:
SELECT * FROM TABLE1
WHERE FK_ID IN (select regexp_substr(:in_str, '[^,]+',1,level) FROM DUAL CONNECT BY INSTR(:in_str,',',1, level)>0);
Строка :in_str обязательно должна заканчиваться запятой, иначе последний параметр в строке будет пропущен.
Сравнение двух способов
С точки зрения удобства первый способ менее удобен чем второй - это очевидно, а с точки оптимизатора запросов есть один ньюанс. При использовании декларативного способа оптимизатор точно знает сколько значений находится в IN и может раскрыть скобки: ... id in (:p1, :p2, :p3) → id=:p1 or id=:p2 or id=:p3, а в случае с рекурсивным способом оптимизатор должен создать виртуальную таблицу и сделать inner join c основной таблицей. Стоит это учитывать.
Комментариев нет:
Отправить комментарий