过滤值的“Smart”where子句(Oracle 10g)

时间:2009-08-11 13:10:34

标签: sql oracle

想象表t1有2个cols:

col1      col2
--------------
test 900     1 
test 901     2
test 902     3
user 901     4
test 909     5

我想找到一行2个参数(名称,代码),其中名称为(test,user ..etc)和代码 - (901,902,null,.. etc)。 不能有多行相同(代码,名称) - 我的意思是在Col1中没有2行有“test 901”。

代码:

declare 
 name varchar2(30);
 code varchar(10);
 col_val varchar2(30);
 col2_val numeric;
begin
 name:= 'test';
 code := '900';

  select col1, col2 into col_val, col2_val 
  from t1 
  where 

   ( REGEXP_LIKE(col1, name||'\s+'||code) -- (3)
   or (
        not   REGEXP_LIKE(col1, name||'\s+'||code) -- (1) 
        and REGEXP_LIKE(col1, name) -- (2)
      )
    )
  order by col1;
  DBMS_OUTPUT.PUT_LINE('val:'||col_val||' id:'||col2_val);
end;

1)测试值名称:='test'代码:='900'结果应为“val:test 900 id:1” - 没关系。

2)但名称:='test'代码:= '909'结果应为“val:test 909 id:5 ”,但我得到了“val:test 900 id:1”(Name ='Test'的第一行) - 这不是我想要的。

3)以防名称:='test'代码:= '999'结果应为“val:test 900 id:1”(没有999代码,所以我需要只是里面有Name ='test'的任何行。

主要问题是为什么oracle忽略(1)子句为2)例子? 也许我做错了 - 所以如果你能表明我的错误就会很棒!

3 个答案:

答案 0 :(得分:0)

你不能像这样组合ROWNUM和ORDER BY,因为ROWNUM是之前的行号。

你需要更详细并写一些像

这样的东西
 select a.* from (
     select * from table order by col1 ) a
  where rownum = 1;

查看ROWNUM和分页的文档。

答案 1 :(得分:0)

这个条件:

(REGEXP_LIKE(col1, :name || '\s+' || :code)
OR (NOT REGEXP_LIKE(col1, :name || '\s+' || :code) AND REGEXP_LIKE(col1, :name))

将匹配示例中的所有行。

搜索test 909时,您正在匹配'test 909' OR (NOT 'test 909' AND 'test')。这将匹配从'test'开始的每一行(每个第一个条件或每秒)。

由于您使用的是rownum = 1,因此返回的第一列匹配为'test 900'

如果你想要一个后备匹配(如果它存在则返回'test 909',否则返回任何'test'),请使用:

SELECT  *
FROM    (
        SELECT  *
        FROM    t1
        WHERE   REGEXP_LIKE(col1, name || '\s+' || code)
        UNION ALL
        SELECT  *
        FROM    t1
        WHERE   REGEXP_LIKE(col1, name)
        )
WHERE   rownum = 1

,或者,如果您不喜欢UNION s:

SELECT  *
FROM    (
        SELECT  *
        FROM    t1
        WHERE   REGEXP_LIKE(col1, name)
        ORDER BY
                CASE WHEN REGEXP_LIKE(col1, name || '\s+' || code) THEN 0 ELSE 1 END
        )
WHERE   rownum = 1

但后者的效率较低,因为它必须排序。

答案 2 :(得分:0)

将col1的各个部分存储在不同的列中会更好。无论如何,除了Thilo所说的,还有一件事。

忽略rownum部分,表的四行与示例中的WHERE子句匹配。英语中的WHERE子句是“名称和代码都匹配,否则它们不匹配,但名称匹配。”

这是一种说“名称匹配”的复杂方式,如果这就是你的意思,就不需要这么复杂的WHERE子句。

(如果\ s表示空格,我不确定,它是“名称匹配,名称后面有空格。”)如果您希望在仅限名称匹配之前看到“两个”匹配,选择此“评分”顺序中的第一行:

ORDER BY 
  CASE WHEN REGEXP_LIKE(col1, name||'\s+'||code) THEN 2 
       WHEN REGEXP_LIKE(col1, name||'\s+) THEN 1
  ELSE 0 END DESC

对评论的回应:

您的WHERE子句无法表达您的要求的但如果不是...... 方面。你的WHERE子句只表达如果有CODE和NAME的行或者只有NAME的行,请显示,这不是你的要求。

要表达 WHERE A,但如果不是A,那么B ,它将不起作用

WHERE <condition A> OR <condition B>

你必须写

WHERE <condition A> OR (NOT <condition A> AND <condition B>)

或做我喜欢的CASE表达式。

这有帮助吗?