【问题标题】:Oracle nvl in where clause showing strange results?Oracle nvl 在 where 子句中显示奇怪的结果?
【发布时间】:2011-07-07 16:14:00
【问题描述】:

我有一个 Web 表单,它允许用户根据传入 proc 的参数搜索和编辑 Oracle 表中的记录。这是我的数据:

CAE_SEC_ID  SEC_CODE  APPR_STATUS
1           ABC1      100
2           ABC2      100
3           ABC3      101
4           (null)    101
5           (null)    102
6           ABC4      103

这里是 where 子句:

select foo 
  from bar 
 where CAE_SEC_ID = NVL(p_cae_sec_id,CAE_SEC_ID)
   and Upper(SEC_CODE) like '%' || Upper(NVL(p_sec_code,SEC_CODE)) || '%'
   and APPR_STATUS = NVL(p_appr_status, APPR_STATUS)

在参数上使用 nvl 应该只返回匹配的记录,如果任何参数有值,则返回所有记录,如果没有参数有值。一切都很标准,我想。但是,当我在没有任何参数值的情况下进行搜索时,查询不会返回带有空 SEC_CODE 的记录,即只返回记录 1、2、3 和 6。上面的 where 子句不应该包含具有空 SEC_CODE 值的记录吗?

【问题讨论】:

    标签: oracle plsql nvl


    【解决方案1】:

    我们也可以像这样写 Jorn 的查询

    select foo from bar 
    where (CASE WHEN p_cae_sec_id is null THEN 'Y'
                WHEN CAE_SEC_ID = p_cae_sec_id THEN 'Y'
                        ELSE 'N'
                        END)='Y'
    and   (CASE WHEN p_sec_code is null THEN 'Y'
                WHEN Upper(SEC_CODE) like '%' || Upper(p_sec_code) || '%' THEN 'Y'
                        ELSE 'N'
                        END)='Y'
    and (CASE WHEN p_appr_status is null THEN 'Y'
                        WHEN APPR_STATUS = p_appr_status THEN 'Y'
                    ELSE 'N'
                    END)='Y'
    

    使其具体化并提高性能。

    【讨论】:

    • 有趣,您能详细说明为什么这会提高性能吗?
    【解决方案2】:

    表达式NULL = NULL 的计算结果为NULL,而不是true,因此不会返回这些行。如果我正确理解要求,您只想过滤参数是否与 null 不同,所以我会像这样重写查询以使过滤器更明确:

    select foo from bar 
    where (p_cae_sec_id is null or CAE_SEC_ID = p_cae_sec_id)
    and (p_sec_code is null or Upper(SEC_CODE) like '%' || Upper(p_sec_code) || '%')
    and (p_appr_status is null or APPR_STATUS = p_appr_status)
    

    现在将 p_sec_code 参数设置为 null 将返回所有行,忽略 SEC_CODE 列中的值。

    【讨论】:

      【解决方案3】:

      问题是表中的SEC_CODE 值为NULL。这意味着 UPPER(sec_code) 是 NULL 并且您的第二个谓词简化为

      and NULL LIKE '%%'
      

      就像 NULL 不等于任何东西,也不等于任何东西,它也不像任何东西。很可能,您想要类似的东西

      and (Upper(SEC_CODE) like '%' || Upper(NVL(p_sec_code,SEC_CODE)) || '%' or
           (sec_code is null and p_sec_code is null))
      

      如果P_SEC_CODE 为NULL,则返回每一行,但如果P_SEC_CODE 为非NULL,则仍应用过滤器。

      【讨论】:

        【解决方案4】:

        不,不应该。

        数据库中的 SEC_CODE 为空,因此 UPPER(SEC_CODE) 为空,因此它将在 LIKE 匹配或几乎任何其他超出 IS NULL 的比较时失败。从技术上讲,它是 UNKNOWN 而不是 FALSE,但不足以通过测试。

        【讨论】:

          猜你喜欢
          • 2011-07-07
          • 2014-07-25
          • 2016-10-04
          • 2015-09-07
          • 2018-03-11
          • 1970-01-01
          • 2019-06-09
          • 2015-01-13
          • 2018-05-28
          相关资源
          最近更新 更多