Plsql PL/SQL";其中;有条件的;其中;条款
我正试图对一个表进行查询,但在构建WHERE子句时遇到了一些困难。表中有一列“SUBCLASS”,其值类似于“UN”或“U*” “U*”表示“U”与任何其他字符(如UB、UC等)的匹配 表如下所示:Plsql PL/SQL";其中;有条件的;其中;条款,plsql,oracle12c,Plsql,Oracle12c,我正试图对一个表进行查询,但在构建WHERE子句时遇到了一些困难。表中有一列“SUBCLASS”,其值类似于“UN”或“U*” “U*”表示“U”与任何其他字符(如UB、UC等)的匹配 表如下所示: ID ISC SUBCLASS --- ---- --------- 1 ABC UN 2 DEF UN 3 DEF U* 给定字符串UC12341001000012或UN12341001000012,我将如何构
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
bind变量来代替较短的文本,部分原因是我认为它更清晰,但也因为对于UC
,我使用的substr()
调用比您使用的要多,这一点并不明显;因为对于完整的较长值,您无论如何只想查看前两个
您可以稍微更改它,使其不重复case表达式(使用另一层内联视图/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
。。。或者,您可以在应用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
完美的非常感谢。只有一个问题:在返回多行的情况下,我在最后一个“WHERE”子句中添加了“ROWNUM=1”以获取最上面的一行,但它仍然返回两行。当我将ROWNUM添加到“Select”时,我可以看到值是1和2;不知道我错过了什么!不要介意;我相信我必须将整个查询包装在一个“select*from”()中,然后将WHERE ROWNUM=1添加到外部选择中。希望这是正确的方法!对,我没有看到对您之前评论的编辑。您还可以添加一个
行号()
在现有的内联视图中。如果您这样做,您可以简化选择,使其最初仍然获得所有三行-但对它们进行排序,使U\*
始终排在最后(加上您从前两行中选择的选项);然后,rownum=1
如果它是唯一的一行,将得到“U*”,如果不是,则无法到达它。@NoBullMan-我已经添加了示例。谢谢;我感谢您的快速响应。
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