Plsql PL/SQL";其中;有条件的;其中;条款

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,我将如何构

我正试图对一个表进行查询,但在构建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
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