我试图对表进行查询,并且在构造WHERE子句时遇到了困难。表有一个“SUBCLASS”列,其值为“UN”或“U *”。
“U *”表示“U”与任何其他字符(例如UB,UC,......)的匹配。
表看起来像:
ID ISC SUBCLASS
--- ---- ---------
1 ABC UN
2 DEF UN
3 DEF U*
给定字符串UC12341001000012或UN12341001000012,我将如何构造WHERE子句。
我试过了:
SELECT * FROM MYTABLE
WHERE x AND y AND
(SUBCLASS='UC' OR SUBSTR(SUBCLASS, 1, 1) = SUBSTR('UC',1,1))
但它返回所有行。 (我在这里使用'UC',但实际上它是传递给存储过程的参数)。
所以,鉴于UC12341001000012,我应该得到第三条记录,鉴于UN12341001000012,我应该得到前两条记录。
当有完全匹配时,(稍微)棘手的位不包括通配符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表达式检查的相同内容(或保留它out - 取决于音量,索引...)等,但希望能给你一个想法。
使用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