Oracle nvl 在 where 子句中显示奇怪的结果?

发布于 2024-10-20 13:46:47 字数 698 浏览 1 评论 0原文

我有一个 Web 表单,允许用户根据传递到过程的参数搜索和编辑 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 应该仅返回匹配的记录,如果没有参数具有值,则返回所有记录。一切都很标准,我是这么想的。但是,当我在没有任何参数值的情况下进行搜索时,查询不会返回具有 null SEC_CODE 的记录,即仅返回记录 1、2、3 和 6。上面的 where 子句不应该包含具有空 SEC_CODE 值的记录吗?

I have a web form that allows users to search on and edit records from an Oracle table based on parameters passed in to a proc. Here's my data:

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

And here's the where clause:

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)

Using nvl on the parameters should return only the matched records if any of the parameters have values, and all records if none of the parameters have values. All pretty standard or so I thought. However when I do a search without any parameter values the query isn't returning records with a null SEC_CODE i.e. only records 1, 2, 3, and 6 are being returned. Shouldn't the where clause above include records with null SEC_CODE values?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

娇柔作态 2024-10-27 13:46:47

问题是表中的 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,则仍应用过滤器。

The problem is that the SEC_CODE value in the table is NULL. That means that UPPER(sec_code) is NULL and your second predicate simplifies to

and NULL LIKE '%%'

Just like NULL is not equal to anything and not unequal to anything, it is not like anything. Most likely, you want something like

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

That will return every row if P_SEC_CODE is NULL but still apply the filter if P_SEC_CODE is non-NULL.

眼泪也成诗 2024-10-27 13:46:47

不,不应该。

数据库中的 SEC_CODE 为空,因此 UPPER(SEC_CODE) 为空,因此在 LIKE 匹配或除 IS NULL 之外的几乎任何其他比较中都会失败。从技术上讲,它是未知的而不是错误的,但不足以通过测试。

No it shouldn't.

The SEC_CODE in the database is null, so the UPPER(SEC_CODE) is null and so it will fail on a LIKE match or pretty much any other comparison beyond IS NULL. Technically it is a UNKNOWN rather than a FALSE but is isn't enough to pass the test.

归属感 2024-10-27 13:46:47

表达式 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 列中。

The expression NULL = NULL evaluates to NULL, which is not true and so these rows won't be returned. If I understand the requirement correctly, you only want to filter if a parameter is different from null, so I would rewrite the query like this to make the filter more explicit:

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)

Setting the p_sec_code parameter to null will now return all rows, ignoring the value in the SEC_CODE column.

红ご颜醉 2024-10-27 13:46:47

我们还可以编写 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'

具体化并提高性能。

We can also write the Jorn's query like

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'

to make it concrete and increase the performance .

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文