关于退货声明的 Oracle 文档
Posted
技术标签:
【中文标题】关于退货声明的 Oracle 文档【英文标题】:Oracle documentation on return statement 【发布时间】:2015-02-13 14:39:59 【问题描述】:它在哪里说“return”语句上的 oracle 函数返回 null。例如,这里是一个简单的函数:
create or replace FUNCTION FOO RETURN NUMBER AS
BEGIN
RETURN;
-- is return null the same as return?
END FOO;
编辑
上述函数不会像 Alex Poole 报告的那样编译。因此,函数必须始终具有返回值,例如数字、日期、blob、clob、varchar2 或 null。它不能只包含“return”。因此,return 在 oracle 中与 return null 不同。
我真正想知道的是它在哪里声明如果函数具有返回某些数据类型(数字、日期、varchar2、blob 或 clob)的签名并且它的主体包含“return null”语句,为什么允许这样做,为什么它可以返回null。我想这与脚本语言相同,例如php:
function foo($i)
if( $i > 0 )
return $i;
return null; // return is the same as return null. Tested in PHP.
当然,这种行为在 C# 中是不允许的,例如:
static int foo() return null;
Error 1 Cannot convert null to 'int' because it is a non-nullable value type
【问题讨论】:
第二个问题:oracle 中的null
和PHP 中的null
不太一样。在 oracle 中,与null
的每个比较都是false
,所以( null > 0)
和(null == 0)
和(null < 0)
或与(null > '0')
相同的都是false
。在 PHP 中的 afaik 取决于上下文,与数字零相比,null
可能评估为零并且条件可以变为 true
。
再次考虑 PHP 应该是这样的:( null == 0)
计算结果为 (false == false)
计算结果为 (true)
。另一方面,( null === 0)
应该评估为false
,因为数据类型也必须匹配。暂时无法测试。无论如何,我更喜欢 Oracles 空逻辑 ;)
在 Oracle 中不是这样 - (null > 0)
、(null = 0)
和 (null < 0)
都评估为未知(因此是 null
),而不是 false
。 Oracle 中的布尔逻辑实际上是三值逻辑——true
、false
和 null
——你必须记住要么迎合或消除 null 情况的可能性。
你显示的内容无法编译;你会得到PLS-00503: RETURN <value> statement required for this return from function
。你只能有一个简单的RETURN
没有表达式in a pipelined function 或一个过程。文档没有说明“return 与 return null 相同”,因为它不是......
@AlexPoole 你当然是对的。嗯..应该先测试函数是否编译。
【参考方案1】:
它在哪里说“return”语句上的 oracle 函数返回 null
它没有在任何地方这么说,因为它不是真的。如果it is pipelined,您只能在函数中使用简单的return
而不是return <expression>
,即数据已经由管道机制返回,并且返回只是表明控制(而不是数据)应该返回到呼叫者,召集者。您还可以在过程中使用普通的return
。您的示例函数无法编译 - 因为没有表达式,您会得到 PLS-00503: RETURN <value> statement required for this return from function
。
函数中return
的行为是described in the PL/SQL subprogram documentation,还有更多关于the return statement的细节,其中提到了expression
:
当 RETURN 语句在流水线表函数中时可选。当 RETURN 语句在任何其他函数中时是必需的。 RETURN 语句在过程或匿名块中时不允许。
RETURN 语句将表达式 的值赋给函数标识符。因此,表达式的数据类型必须与函数的RETURN子句中的数据类型兼容。
所以您修改后的问题实际上是在询问最后一句话;为什么无论声明的返回数据类型如何,您都可以分配null
。但是您可以将 null 分配给大多数数据类型,并且正如 Boneist 指出的那样,大多数数据类型的变量都被初始化为 null。将数字变量设置为 null 是有效的。该文档页面前面的一行说:
RETURN 语句将指定的值赋给函数标识符
... 当您调用函数时,return 语句非常有效地将表达式评估为调用者变量的任何值赋值。 (显然这是一个简单的视图;可能有多个级别的调用者,并且您可能从普通 SQL 调用它,因此没有 PL/SQL 分配,而且内部可能更复杂)。
只要变量是可以为null的类型,就没有违规。虽然它并没有像您希望的那样明确设置 - 更重要的是没有什么说您不能返回 null。如果是这种情况,那将是在正常数据类型限制之上对函数返回的限制。
有点跑题了,也有例外;如果你的数据类型是restricted to not-null values,比如simple_integer
,那么返回null的函数是有效的:
create or replace FUNCTION FOO RETURN NUMBER AS
BEGIN
RETURN NULL;
END FOO;
/
FUNCTION FOO compiled
...但是调用它并尝试将值分配给受约束的变量将失败:
declare
n simple_integer := 0;
begin
n := foo;
end;
/
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 4
如果你在函数声明中使用受约束的数据类型,你就不能显式返回 null:
create or replace FUNCTION FOO RETURN SIMPLE_INTEGER AS
BEGIN
RETURN NULL;
END FOO;
/
FUNCTION FOO compiled
Errors: check compiler log
show_errors 显示:
3/10 PLS-00382: expression is of wrong type
3/3 PL/SQL: Statement ignored
您仍然可以返回一个 评估 为 null 的表达式,编译器无法捕获该表达式(例如 RETURN 1 * NULL
),但在运行它时仍然会出现错误:
declare
n number;
begin
n := foo;
end;
/
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "***.FOO", line 3
ORA-06512: at line 4
【讨论】:
测试了你所有的案例。欺骗编译器的好技巧。空值意味着变量没有值。它不同于具有值空间“”的变量。特别是在 sql 中,行是可选的(可为空的),这意味着就像提到的那样,它可以没有价值。这与例如 C# 不同,其中 int a 的默认值为 0(它也不能有 null 值,不会编译)。 Null 表示该值是未知的,有些人可能认为这在语义上与没有值不同,可能是 *8-)。但是,是的,不同于零或空格; Oracle 也将空字符串视为 null,布尔值甚至可以为 null。我会说 C#int
的行为类似于 Oracle 的 simple_integer
在您在问题中显示的分配中;除了 Oracle 类型没有默认值外,你必须在声明它时分配一些东西,并且不能让它默认为 null。 PHP 版本的行为更像pls_integer
,因为它允许为空。也许吧。
请阅读mariadb.com/kb/en/sql-99/the-meaning-of-null - null 表示缺少的值,要么是因为我们不知道它,要么是因为它不适用。 NULL / 未知或 NULL / 不适用。【参考方案2】:
我认为您不会在文档中明确针对函数找到这样的声明。但是,如果您在this bit of the documentation about declarations 中看到By default, variables are initialized to NULL...
。因此,如果不初始化返回值,会自动为NULL。
ETA:哈哈,我应该先测试该函数,根据 Alex 的评论,它无法编译。但我认为不将变量定义为 null 的一般原则仍然存在于其他地方 *:-)
【讨论】:
尽管如此,您仍然会使用RETURN <expr>
,而不仅仅是RETURN
。不确定我是否真的理解这个问题 *8-)
确实;我必须记得在将来回复之前测试一下! *;-)以上是关于关于退货声明的 Oracle 文档的主要内容,如果未能解决你的问题,请参考以下文章
React JS:渲染的钩子比预期的要少。这可能是由于意外提前退货声明造成的