我正在寻找创建一个不接受任何参数并返回所有结果的函数的最佳方法,但也接受参数并返回这些结果。
我在工作中一直在处理的标准是:
FUNCTION get_records (
i_code IN records.code%type := NULL,
i_type IN records.type%type := NULL
) RETURN results
问题是我想要返回类型为NULL的记录,并使用:
WHERE type = nvl(i_type, type)
由于显而易见的原因,它只返回具有实际类型而不是空记录的记录。我只是想知道是否有一种标准的方法可以在我们使用的所有功能中实现。巧合的是,如果我提供参数......我不想要该字段的NULL值。
答案 0 :(得分:5)
为什么不简单地添加
type = i_type OR (i_type IS NULL AND type IS NULL)
这样,当传入的param为null时,它会查找所有内容(包括空值)或指定的值。现在,如果你只想要空值......
示例(将值从null更改为5,您将看到输出)
WITH TESTDATA AS (
SELECT LEVEL dataId
FROM DUAL
CONNECT BY LEVEL <= 100
UNION
SELECT NULL
from dual
)
SELECT *
FROM TESTDATA
where dataId = :n or (:n is null AND dataId is null) ;
然而:n = 6 结果将是
DATAID
----------------------
6
(删除了一个新帖子,误读了一个参数) 但我喜欢新的方法并避开NVL
如果你不对动态sql不感兴趣,这是一个很好的方法
http://www.oracle.com/technetwork/issue-archive/2009/09-jul/o49asktom-090487.html
答案 1 :(得分:4)
解决此问题的标准方法是重载函数,而不是使用默认值:
FUNCTION get_records (
i_code IN records.code%type,
i_type IN records.type%type
) RETURN results;
FUNCTION get_records (
i_code IN records.code%type
) RETURN results;
FUNCTION get_records RETURN results;
注意:如果您还需要一个版本i_type
,如果它与i_code
具有相同的基础类型,则可能会遇到问题 - 在这种情况下,您需要使用其他名称功能。
答案 2 :(得分:3)
我想我会猜测使用DEFAULT
关键字可以解决问题,不是吗? (以下链接将提供更多详细信息。)
CREATE OR REPLACE FUNCTION get_records (
i_code IN records.code%type DEFAULT NULL,
i_type IN records.type%type DEFAULT NULL
) RETURN results
编辑#1
如果我正确理解了这个问题,那么当i_type
参数为NULL时,您希望返回所有记录。如果没有进一步的细节,我的猜测将如下。
CREATE OR REPLACE FUNCTION get_records (
i_code IN records.code%TYPE DEFAULT NULL,
i_type IN records.type%TYPE DEFAULT NULL
) RETURN results
BEGIN
IF (i_type IS NULL) THEN
select *
from table
ELSE
select *
from table
where type = NVL(i_type, type)
END IF
EXCEPTION
WHEN OTHERS THEN
NULL
END
这就是我可以用所提供的信息做的全部,尽管功能正文如下所述。
编辑#2
我对Oracle有点生疏,所以我查阅了下面链接的一些文档:
正如我已经阅读过的那样,您最好使用NVL
指令中的SELECT
函数,而不是WHERE
条款。
最后,你的问题到底是什么?你能说清楚吗?
答案 3 :(得分:3)
重申我对此问题的理解:您不能将默认值NULL
表示“返回所有记录”,因为当前预期的行为是它将仅返回值为实际上是NULL。
一种可能性是添加对应于每个查找参数的布尔参数,该参数指示是否应该实际用于过滤结果。这可能是一个问题,调用者可能会指定一个查找值,但无法将该标志设置为true,从而产生意外结果。如果NULL
以外的任何查找值的标志为false,则可以在运行时通过引发异常来防范此情况。
另一种可能性是为每个查阅列定义域外值 - 例如如果为参数传递字符串'ANY',则不会过滤该列的值。只要您能为每列找到有价值的哨兵值,这应该可以正常工作。我建议在某些包中将sentry值声明为常量,以便对函数的调用看起来像get_records( PKG.ALL_CODES, 'type1' )
。
答案 4 :(得分:1)
我一直在使用以下hack(假设p_product是可选的过程输入):
其中t.product = decode(p_product,null,t.product,p_product)
procedure get_data(p_product in number := null)
...
select *
from tbl t
where t.product = decode(p_product, null, t.product, p_product);
...
当产品未传入时,这将创建“where 1 = 1”场景,否则使用该产品。一个可能的主要缺点是,无论参数如何,它都会解析到相同的执行计划。