ORACLE PL/SQL:函数和可选参数,如何?
Posted
技术标签:
【中文标题】ORACLE PL/SQL:函数和可选参数,如何?【英文标题】:ORACLE PL/SQL: Functions and Optional Parameters, How? 【发布时间】:2010-10-19 17:27:57 【问题描述】:我正在寻找创建一个函数的最佳方法,该函数可以不接受参数并返回所有结果,但也可以接受参数并返回这些结果。
我在工作中一直在处理的标准是:
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 值。
【问题讨论】:
【参考方案1】:为什么不简单地添加
type = i_type OR (i_type IS NULL AND type IS 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
【讨论】:
我建议将其更改为type = i_type OR i_type IS NULL
。根据我的经验,这比使用 NVL() 更有可能利用 type
上的索引。另外,对我来说似乎更清楚。
@Dave:这就是我实施的解决方案。
这种方式一般不可sargable【参考方案2】:
解决这个问题的标准方法是重载函数,而不是使用默认值:
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
具有相同的底层类型,您可能会遇到麻烦 - 在这种情况下,您需要为函数使用不同的名称。
【讨论】:
@OMG:好吧,我的解决方案没有说明是否使用动态 SQL - 关键是,你如何区分 get_records(NULL,NULL) 和 get_records(NULL),除非你让为参数默认设置一些“神奇值”?重载是解决这个问题的最好方法,IMO。【参考方案3】:就在我的脑海中,我猜想使用 DEFAULT
关键字可以解决问题,不是吗? (以下链接将提供更多详细信息。)
Using the DEFAULT keyword.
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 有点生疏,所以我查阅了一些文档,链接如下:
Oracle/PLSQL: NVL Function
正如我所读,您最好在您的SELECT
指令中使用NVL
函数,而不是您的WHERE
子句。
最后,你的问题到底是什么?能说清楚吗?
【讨论】:
参数声明中的:=
与DEFAULT
相同。问题似乎是参数的 NULL 值意味着将记录与相应列中的 NULL 值匹配;那么应该使用什么默认值来表示“所有记录”?
也不返回类型为 NULL 的记录。如果我提供参数,我基本上想等于类型,否则不要使用参数。这不是动态 SQL,因此您可以看到困境。如果是,我会排除该子句。
@Dave Costa:感谢您提供的信息。我一直并且只使用 DEFAULT
关键字,而不是等号 (:=
) 来定义默认值。
@jlrolin:您能否提供一个函数体的示例代码,以及您从中提取数据的数据表中的数据示例?这可能会带来一些其他解决方案的想法。
@Will:函数体是一个简单的 SELECT * FROM table WHERE type = nvl(i_type, type),被输入到 ref_cursor,然后返回。【参考方案4】:
重申我对这个问题的理解:您不能将NULL
的默认值表示“返回所有记录”,因为当前预期的行为是它只会返回值实际上为 NULL 的那些记录.
一种可能性是为每个查找参数添加一个布尔参数,该参数指示是否应该实际使用它来过滤结果。一个潜在的问题是调用者可能会指定一个查找值,但未能将标志设置为 true,从而产生意外的结果。如果对于除NULL
之外的任何查找值的标志为假,您可以在运行时通过引发异常来防止这种情况发生。
另一种可能性是为每个查找列定义一个域外值——例如如果为参数传递了字符串“ANY”,则它不会过滤该列上的值。只要您可以为每列找到有价值的哨兵值,这应该可以正常工作。我建议在某个包中将哨兵值声明为常量,以便对函数的调用看起来像 get_records( PKG.ALL_CODES, 'type1' )
。
【讨论】:
【参考方案5】:我一直在使用以下 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”场景,否则将使用该产品。一个潜在的主要缺点是,无论参数如何,它都会解析到相同的执行计划。
【讨论】:
以上是关于ORACLE PL/SQL:函数和可选参数,如何?的主要内容,如果未能解决你的问题,请参考以下文章
如何在Oracle中仅将列用作1行到1行返回pl / sql函数中的参数
where 条件中的可选参数 - 如何提高性能 - PL/SQL