Oracle:在 Where 子句中使用 Case 语句

Posted

技术标签:

【中文标题】Oracle:在 Where 子句中使用 Case 语句【英文标题】:Oracle: Using Case Statement in Where Clause 【发布时间】:2017-03-28 12:56:06 【问题描述】:

在 Oracle 12(和 APEX)中,我遇到了 WHERE 子句中的 CASE 语句的问题。该场景是一个主表、ORDER 和一个 PRODUCTS_BOUGHT 表,因此这是一对多的关系。我有一份报告,在 PRODUCTS_BOUGHT 上有一个过滤器。过滤器填充名为:P36_PRODUCT_LISTING 的绑定变量/APEX 页面项。如果用户选择给定产品,我希望报告仅显示包含给定产品的订单。过滤器包含不应进行任何过滤的单词“All”,以及我们携带的每个产品。

我的SQL语句是

Select distinct   
    :P36_PRODUCT_LISTING,    
     LISTAGG(product_name, ', ') WITHIN GROUP (ORDER BY product_name)   OVER (PARTITION BY B.SALES_ORDER_NUMBER) AS products,
    ...
from ORDER A, PRODUCTS_BOUGHT B
where 
 A.SALES_ORDER_NUMBER = B.SALES_ORDER_NUMBER
 and
case when
 :P36_PRODUCT_LISTING = 'All' then 1 = 1
else a.SALES_ORDER_NUMBER IN (SELECT SALES_ORDER_NUMBER from PRODUCTS_BOUGHT where PRODUCT_NAME = :P36_PRODUCT_LISTING) end 

当我运行语句时,我得到的错误是缺少关键字。 我做错了什么?

【问题讨论】:

使用 AND/OR 代替大小写! 【参考方案1】:

不要使用case。只需使用布尔逻辑:

where (:P36_PRODUCT_LISTING = 'All' or
       a.SALES_ORDER_NUMBER IN (SELECT SALES_ORDER_NUMBER
                                from PRODUCTS_BOUGHT
                                where PRODUCT_NAME = :P36_PRODUCT_LISTING
                               ) 
      ) 

case(如您所写)的问题在于 Oracle 不会将逻辑表达式中的值视为有效值。有些数据库可以,但 Oracle 不行。

另外:

不要在from 子句中使用逗号。始终使用正确、明确的 join 语法。 使用作为表名缩写的表别名。更容易阅读查询和修复错误。 select distinct 在这里不需要。您正在进行没有group by 的聚合,所以无论如何只有一行。

所以:

 Select :P36_PRODUCT_LISTING,    
        LISTAGG(b.product_name, ', ') WITHIN GROUP (ORDER BY b.product_name)   OVER (PARTITION BY B.SALES_ORDER_NUMBER) AS products,
    ...
from ORDER o join
     PRODUCTS_BOUGHT B
     on p.SALES_ORDER_NUMBER = B.SALES_ORDER_NUMBER
    where (:P36_PRODUCT_LISTING = 'All' or
           o.SALES_ORDER_NUMBER IN (SELECT SALES_ORDER_NUMBER
                                    from PRODUCTS_BOUGHT
                                    where PRODUCT_NAME = :P36_PRODUCT_LISTING
                                   ) 
          ); 

【讨论】:

我真的开始怀疑,到底谁还在教旧的连接语法?它已经过时了将近 10 年 不是谁在教旧语法的问题,而是我 20 年前学的语法的问题... ;)【参考方案2】:

Case 旨在返回一个值,而不是一个语句..

试试 OR

where :P36_PRODUCT_LISTING = 'All' 
or (:P36_PRODUCT_LISTING <> 'All'
    and a.SALES_ORDER_NUMBER IN (SELECT SALES_ORDER_NUMBER from PRODUCTS_BOUGHT where PRODUCT_NAME = :P36_PRODUCT_LISTING))

【讨论】:

以上是关于Oracle:在 Where 子句中使用 Case 语句的主要内容,如果未能解决你的问题,请参考以下文章

where 子句 oracle 中的 case 语句

Oracle中where子句中的case表达式

Oracle where 子句中的 case 表达式

Oracle SQL的Where子句中如何写case语句?

Oracle SQL 不同的 where 子句与 case when

在 where 子句中执行 Oracle 查询