我正在尝试对表进行查询,并且在构建WHERE子句时遇到了麻烦。表的“ SUBCLASS”列的值类似于“ UN”或“ U *”。
“ U *”表示匹配“ U”和任何其他字符(例如UB,UC,...)。
表格如下:
PDO::ATTR_PERSISTENT
给出一个字符串UC12341001000012或UN12341001000012,我将如何构造WHERE子句。
我尝试过:
ID ISC SUBCLASS
--- ---- ---------
1 ABC UN
2 DEF UN
3 DEF U*
,但它返回所有行。 (我在这里使用“ UC”,但实际上这是一个传递给存储过程的参数。)
因此,给定UC12341001000012,我应该得到第三条记录,给定UN12341001000012,我应该得到前两条记录。
答案 0 :(得分:1)
存在完全匹配项时,(略)棘手的位不包括通配符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()
个电话;因为使用更长的完整值,无论如何您只想看前两个。
您可以对其进行一些更改以不重复case表达式(然后再从另一层inline view / 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