(немного) хитрый бит не включает строку подстановки U*
, когда есть точные совпадения.Существуют различные подходы с подзапросами и объединениями и т. Д .;этот использует встроенное представление для пометки и подсчета точных и подстановочных совпадений, а затем фильтрует это встроенное представление:
select id, isc, subclass, exact, wild
from (
select id, isc, subclass,
case when subclass = substr(:str, 1, 2) then 'Y' end as exact,
case when subclass = substr(:str, 1, 1) || '*' then 'Y' end as wild,
count(case when subclass = substr(:str, 1, 2) then subclass end) over () as exact_cnt
from mytable
where subclass like substr(:str, 1, 1) || '%' -- optional
)
where exact = 'Y' or (wild = 'Y' and exact_cnt = 0)
Я использовал переменную связывания :str
вместо вашего более короткого литерала, частичнопотому что я думаю, что это более понятно, но также потому, что только с UC
непонятно, почему я использовал substr()
вызовов больше, чем вы;поскольку с вашими полными более длинными значениями вы все равно хотите смотреть только на первые два.
Вы можете немного изменить его, чтобы не повторять выражение регистра (с другим слоем встроенного представления / CTE, который вы затем посчитаете из), или измените внутренний фильтр, чтобы явно искать те же вещи, которые проверяет выражение case (или не включать его - зависит от объема, индексов ...) и т. д., но, надеюсь, дает вам идею.
С CTE для предоставления данных образца подкласса:
var str varchar2(20);
exec :str := 'UC12341001000012';
-- CTE for sample data
with mytable (id, isc, subclass) as (
select 1, 'ABC', 'UN' from dual
union all select 2, 'DEF', 'UN' from dual
union all select 3, 'DEF', 'U*' from dual
)
-- actual query
select id, isc, subclass
from (
select id, isc, subclass,
case when subclass = substr(:str, 1, 2) then 'Y' end as exact,
case when subclass = substr(:str, 1, 1) || '*' then 'Y' end as wild,
count(case when subclass = substr(:str, 1, 2) then subclass end) over () as exact_cnt
from mytable
where subclass like substr(:str, 1, 1) || '%' -- optional
)
where exact = 'Y' or (wild = 'Y' and exact_cnt = 0);
ID ISC SU
---------- --- --
3 DEF U*
exec :str := 'UN12341001000012';
<same query>
ID ISC SU
---------- --- --
1 ABC UN
2 DEF UN
в случае возвращения нескольких строк
Если вам нужна только одна из строк с точным соответствиемВы можете добавить вызов row_number()
во встроенном представлении - с подходящим значением order by
для того, чтобы разделить связи, а затем добавить его во внешний фильтр:
select id, isc, subclass
from (
select id, isc, subclass,
case when subclass = substr(:str, 1, 2) then 'Y' end as exact,
case when subclass = substr(:str, 1, 1) || '*' then 'Y' end as wild,
count(case when subclass = substr(:str, 1, 2) then subclass end) over () as exact_cnt,
row_number() over (partition by subclass order by isc) as rn
from mytable
where subclass like substr(:str, 1, 1) || '%' -- optional
)
where (exact = 'Y' or (wild = 'Y' and exact_cnt = 0))
and rn =1
... илиВы можете изначально выбрать все три строки, но расположить их так, чтобы подстановочный знак был последним, прежде чем применять фильтр rownum
:
select id, isc, subclass
from (
select id, isc, subclass
from mytable
where subclass = substr(:str, 1, 2)
or subclass = substr(:str, 1, 1) || '*'
order by case when subclass like '_*' then 2 else 1 end,
isc -- or however you want to split ties
)
where rownum = 1