为什么SQL中的这些NVL()语句错误?

时间:2013-02-12 13:56:23

标签: sql oracle

SELECT inv_no,NVL2(inv_amt,inv_date,'Not Available')
FROM invoice;

SELECT inv_no,NVL2(inv_amt,inv_amt*.25,'Not Available') FROM invoice;

获得

ORA-01858: a non-numeric character was found where a numeric was expected
ORA-01722: invalid number

分别 请建议我在expr1和expr2中给出的数据类型是什么。

还请告诉我这是怎么回事?

SELECT inv_no,NVL2(inv_date,sysdate-inv_date,sysdate)
FROM invoice

3 个答案:

答案 0 :(得分:6)

NVL2的第2和第3个参数应该是相同的数据类型。因此,假设inv_date是DATE,则需要将其设为varchar2之类;

SELECT inv_no, NVL2(inv_amt, to_char(inv_date, 'dd-mon-yyyy hh24:mi:ss'), 'Not Available') FROM ...

或您想要的任何格式字符串。否则,Oracle将转换第3个参数'Not Available'以匹配第2个参数的数据类型。这会尝试将'Not Available'转换为日期并崩溃。

同样在第二个示例中,您必须通过inv_amt*.25to_char转换为字符,例如to_char(inv_amt*.25)

答案 1 :(得分:1)

您的前两个示例尝试为同一字段生成日期/数字和文本结果。当Oracle尝试将此文本转换为任一类型时,这将导致错误。您需要使用日期/数字字段上的to_char(field)函数将它们转换为文本。

最后,日期实际上是添加到数据库基准日期的数字。例如,日期是基准日的数量,它具有的小数是一天的比率,例如0.5是12小时,并且数据库具有基准日期,例如01-Jan-190001-Jan-2000。这就是为什么当你date - date时,结果是数字,日期也可以表示为数字。

答案 2 :(得分:1)

请参阅:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions106.htm

第二个参数应该是字符或数字。第二个参数给出了第三个参数将被隐式转换的数据类型。所以:

<强> 1。第一个
SELECT NVL2(NULLIF(1, 1), SYSDATE, 'A') FROM DUAL; -- FAILS; SELECT NVL2(NULLIF(1, 0), SYSDATE, 'A') FROM DUAL; -- FAILS; SELECT NVL2(NULLIF(1, 1), 'A', SYSDATE) FROM DUAL; -- PASS; returns SYSDATE (as char datatype) SELECT NVL2(NULLIF(1, 0), 'A', SYSDATE) FROM DUAL; -- PASS; returns 'A';
是不正确的,因为您不能将DATE作为第二个参数。

以同样的方式:

SELECT inv_no,NVL2(inv_amt,inv_amt*.25,'Not Available') FROM invoice;

<强> 2。第二个也是无效的:
SELECT inv_no,NVL2(inv_amt,'Not Available',inv_amt*.25) FROM invoice;
Oracle尝试将第三个参数隐式转换为第二个参数的数据类型,这意味着它尝试将“不可用”转换为数值

当你交换第二和第三个参数时它会起作用:

SELECT inv_no,NVL2(inv_amt,TO_CHAR(inv_amt*.25), 'Not Available') FROM invoice;

inv_amt * .25将隐式转换为字符数据;这个例子没用,因为它会让你为NULL * .25使它为NULL。

但是,您可以通过将数字结果转换为字符来将两个参数都设为字符:

SELECT NVL2(2, SYSDATE - TO_DATE('10-JAN-83'), SYSDATE) from dual; -- PASSES
SELECT NVL2(2, 2.2, SYSDATE) from dual; -- FAILS.

特别是当您想要显示货币时,它会有所帮助。

第3。第三个更复杂

我能解释的唯一方法是在处理第三个参数之前将第二个参数转换为字符。这样第三个也将被转换为角色。鉴于这两种情况,这是有道理的:

Unexpected token

最后:我建议坚持使用Oracle的文档并使用显式转换。