oracle sql中的谓词优先级

时间:2018-03-06 18:40:54

标签: sql oracle

我有一个查询,我需要根据谓词首选项的降序从表中返回一行。例如:

SELECT  *
FROM    Tbl
WHERE   col = 1
OR      col = 2 
OR      col = 3;

在上面的场景中,如果col = 1,我不想返回col = 2或3的数据,只有col = 1的数据。

如果col!= 1但col = 2或3,我只想返回col = 2的数据,依此类推。

有没有简单的方法来实现这一目标?如果我解释这一点的方式令人困惑,请提前道歉。

修改

要清除这种混淆,请参阅以下示例数据:

With tbl As (
Select  1 As RECORD_ID, 'This is the string I want to return' str,                            'FIRST'  priority   From dual Union All
Select  1,              'This is the string i want to return, if CONDITION1 does not exist',  'SECOND'            From dual Union All
Select  1,              'this is the string i will return if i find no others',               'DEFAULT'           From dual Union All
Select  2,              'This is the string i want to return, if CONDITION1 does not exist',  'SECOND'            From dual Union All
Select  2,              'this is the string i will return if i find no others',               'DEFAULT'           From dual
)
Select  RECORD_ID,
        str
From    tbl
Where   xxx;

所以在上面的例子中,如果我查询了RECORD_ID 1,我希望返回FIRST字符串,如果我查询了RECORD_ID 2,我应该得到SECOND。

此刻,所有三个字符串都将返回。

4 个答案:

答案 0 :(得分:1)

一种方法使用排序:

care_team_member_name   care_team_member_Engagement_id  care_team_member_start_date care_team_member_end_date
TM-000022181            a1Y0q0000000woaEAA               2017-08-16                  NULL
TM-000022182            a1Y0q0000000wobEAA               2017-08-16                  NULL
TM-000022183            a1Y0q0000000wocEAA               2017-08-16                  NULL
TM-000022184            a1Y0q0000000wodEAA               2017-08-16                  NULL
TM-000022185            a1Y0q0000000woeEAA               2017-08-16                  NULL
TM-000030523            a1Y0q0000000woVEAQ               2018-01-03                  2018-02-28
TM-000031508            a1Y0q0000000woVEAQ               2018-01-25                  2018-02-28
TM-000031798            a1Y0q0000000woVEAQ               2018-03-01                  2018-03-05
TM-000031802            a1Y0q0000000woVEAQ               2018-03-01                  2018-03-05
TM-000031803            a1Y0q0000000woVEAQ               2018-03-01                  2018-03-05
TM-000031805            a1Y0q0000000woVEAQ               2018-03-01                  2018-03-05
TM-000031806            a1Y0q0000000woVEAQ               2018-03-01                  2018-03-05
TM-000023500            a1Y0q0000000woVEAQ               2017-09-21                  2018-03-05
TM-000023503            a1Y0q0000000woVEAQ               2017-09-22                  2018-03-05

显然,在您的情况下,select t.* from (select t.* from t where col in (1, 2, 3) order by (case col when 1 then 1 when 2 then 2 when 3 then 3 end) ) t where rownum = 1; 可能是order by,但一般情况是使用order by col

答案 1 :(得分:0)

你可以尝试:

SELECT  t1.*
FROM    Tbl t1
WHERE   t1.col in (1,2,3)
ORDER BY t1.col
FETCH FIRST 1 ROWS ONLY;

答案 2 :(得分:0)

执行此操作的标准和常见方法是使用ROW_NUMBER()。 Oracle ROWNUM不可移植:

WITH data AS (
    SELECT t.*, ROW_NUMBER() OVER (ORDER BY LENGTH(priority)) AS rn
    FROM Tbl t WHERE col in (1, 2, 3)
)
SELECT * FROM data WHERE rn = 1;

以下是使用min()代替的其他变体,基本相同。 编辑:根据更新的要求,这些将进行调整以获得正确的顺序,但原则上它们仍可以正常工作。

SELECT * FROM Tbl
WHERE col = (SELECT MIN(col) FROM Tbl);

更像第一个:

WITH data AS (
    SELECT t.*, MIN(col) OVER () AS mn
    FROM Tbl t WHERE col in (1, 2, 3)
)
SELECT * FROM data WHERE col = mn;

您可能希望查看查询计划以确定哪一个最适合您,尽管我怀疑您的表只有几行。

答案 3 :(得分:0)

根据每个谓词的选择性,您可以通过将查询分成单个组件来获益,即

SQL> select * from
  2  ( select x
  3    from   t1
  4    where  x = :b1   -- first condition
  5    union all
  6    select x
  7    from   t1
  8    where  y = :b1   -- second condition
  9  )
 10  where rownum = 1
 11  /

如果UNION ALL中的第一个查询找到一行,那么我们可以完全避免第二个查询。

你可以在这里找到一个证明“短路”处理的工作实例

https://connor-mcdonald.com/2016/03/14/the-first-matching-row/