select *
from employee
where employee_id = nvl(:employee_id, employee_id)
and dept = nvl(:dept, dept)
and location = nvl(:location, location)
and unit = nvl(:unit, unit)
SELECT *
FROM EMPLOYEE
WHERE (EMPLOYEE_ID = :p_EMPLOYEE_ID OR :p_EMPLOYEE_ID IS Null)
AND (DEPT = :p_DEPT OR :p_DEPT IS Null)
AND (LOCATION = :p_LOCATION OR :p_LOCATION IS Null)
AND (UNIT = :p_UNIT OR :p_UNIT IS Null)
5条答案
按热度按时间ca1c2owp1#
这背后的原因是,按照Jon建议的方式使用
nvl
有一个缺点:如果被测试的字段是null
本身,它将在该测试中返回false
,因为(我相信)为了测试null
,你需要用is null
来测试它。nvl
可能在那里执行null = null
而不是null is null
,返回错误的数据,您甚至不会注意到,因为它不会警告您。使用
coalesce
,当参数和字段都是null
时,您将获得-1 = -1
(或您认为列不可能的任何其他值i34xakig2#
编写代码的唯一安全方法是基于他们选择的内容的各个视图,例如,如果您使用Java GUI,则可以根据他们想要搜索的内容选择信息。
up9lanfz3#
如果在 predicate 中使用
NVL
,Oracle可能会构建一个优化良好的查询:上面的代码基本上相当于LeoLozes的答案。虽然他的答案更可读,但在这种情况下,神秘版本可能会运行得更快。一个重要的区别是,如果列为NULL,上述代码将不起作用。如果你有可空的列,你需要使用类似LeoLoze的答案,因为
null = null
不是真的。Oracle已经习惯了
NVL
技巧,可以使用FILTER操作自动将此静态查询转换为动态查询。执行计划将有一个完整的表扫描和索引范围扫描,并将在运行时选择适当的一个,这取决于绑定变量的值。请参阅我的答案here,以获得一些演示如何工作的示例代码。o8x7eapl4#
好吧,总是有(非常糟糕的优化)这样做的选择:
我只在有少量行的表中使用它。然而,建议至少有一个强制参数,将使用索引字段(因为在这里,你将有一个 * 表访问完整 *)。
lg40wkob5#
对于真实的世界的应用程序,我建议不要使用这种想法。向数据库提交动态风格的查询在安全性、优化和功能正确性方面已经证明了问题。由于用户界面和数据库之间会有一些应用程序代码,因此最好根据需要构建查询,然后提交执行。