在 Oracle 中处理异常
Handling exception in Oracle
我正在尝试解析作为字符串输入的年份(请不要让我开始 - 它就是这样)。然而,输入的年份无法被 TO_NUMBER
.
解析
WITH src AS (
SELECT '2000' AS y FROM DUAL
UNION SELECT '1991' AS y FROM DUAL
UNION SELECT '20--' AS y FROM DUAL
UNION SELECT '09' AS y FROM DUAL
UNION SELECT '11' AS y FROM DUAL
UNION SELECT '95' AS y FROM DUAL
)
BEGIN
SELECT
s.y,
TO_NUMBER(s.y) AS p
FROM src s
EXCEPTION
WHEN INVALID_NUMBER THEN NULL
END
我从未在 Oracle 中进行过异常处理,如果这是一个基本问题,我深表歉意。
当 运行 我上面的查询时,我得到 ORA-00928: missing SELECT keyword
然后它突出显示 BEGIN
关键字。通过搜索,我看到人们所做的就是使用 BEGIN SELECT
,这也是我正在做的。我猜我在其他地方搞砸了?
基本上我想做的是解析字符串,如果抛出异常我将把它设置为 NULL
.
编辑
我尝试了一种不同的方法并添加了一些分号,正如@DavidFaber 在下面评论的那样。
BEGIN
SELECT
s.y,
TO_NUMBER(s.y) AS p
FROM (
SELECT '2000' AS y FROM DUAL
UNION SELECT '1991' AS y FROM DUAL
UNION SELECT '20--' AS y FROM DUAL
UNION SELECT '09' AS y FROM DUAL
UNION SELECT '11' AS y FROM DUAL
UNION SELECT '95' AS y FROM DUAL
) s;
EXCEPTION
WHEN INVALID_NUMBER THEN NULL;
END;
我现在收到一个不同的错误 ORA-06550: line 2, column 3: PLS-00428: an INTO clause is expected in this SELECT statement
。
SQL中没有异常处理;您需要创建一个 PL/SQL 块来处理异常(请注意,我将您的 UNION
更改为 UNION ALL
):
BEGIN
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(s.y) AS p
FROM src s;
EXCEPTION
WHEN INVALID_NUMBER THEN NULL;
END;
/
但是您可以使用正则表达式来执行 "safe" 数字转换,而不是使用 PL/SQL 块:
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(REGEXP_SUBSTR(s.y, '^\d+'))
FROM src s;
以上会将值 20--
转换为 20
,这可能不是您想要的 - 在这种情况下,请尝试使用此模式 ^\d+$
:
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(REGEXP_SUBSTR(s.y, '^\d+$'))
FROM src s;
希望对您有所帮助。
是的,确实如此,但有内联函数 (Oracle 12c) 之类的解决方法:
WITH FUNCTION safe_to_NUMBER(input IN VARCHAR2)
RETURN NUMBER IS
i NUMBER;
BEGIN
i:= TO_NUMBER(input);
RETURN i;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
SELECT sub.y, safe_to_NUMBER(sub.y)
FROM (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
) sub;
结果:
Y SAFE_TO_NUMBER(SUB.Y)
---- ---------------------
2000 2000
1991 1991
20--
09 9
11 11
95 95
6 rows selected.
我当然不会写这样的生产代码:)
正确方法(DEFAULT NULL ON CONVERSION ERROR
- 从 Oracle12cR2 开始可用):
SELECT sub.y, TO_NUMBER(sub.y DEFAULT NULL ON CONVERSION ERROR) AS y
FROM (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
) sub;
输出:
Y Y
---- ----------
2000 2000
1991 1991
20--
09 9
11 11
95 95
6 rows selected.
我正在尝试解析作为字符串输入的年份(请不要让我开始 - 它就是这样)。然而,输入的年份无法被 TO_NUMBER
.
WITH src AS (
SELECT '2000' AS y FROM DUAL
UNION SELECT '1991' AS y FROM DUAL
UNION SELECT '20--' AS y FROM DUAL
UNION SELECT '09' AS y FROM DUAL
UNION SELECT '11' AS y FROM DUAL
UNION SELECT '95' AS y FROM DUAL
)
BEGIN
SELECT
s.y,
TO_NUMBER(s.y) AS p
FROM src s
EXCEPTION
WHEN INVALID_NUMBER THEN NULL
END
我从未在 Oracle 中进行过异常处理,如果这是一个基本问题,我深表歉意。
当 运行 我上面的查询时,我得到 ORA-00928: missing SELECT keyword
然后它突出显示 BEGIN
关键字。通过搜索,我看到人们所做的就是使用 BEGIN SELECT
,这也是我正在做的。我猜我在其他地方搞砸了?
基本上我想做的是解析字符串,如果抛出异常我将把它设置为 NULL
.
编辑
我尝试了一种不同的方法并添加了一些分号,正如@DavidFaber 在下面评论的那样。
BEGIN
SELECT
s.y,
TO_NUMBER(s.y) AS p
FROM (
SELECT '2000' AS y FROM DUAL
UNION SELECT '1991' AS y FROM DUAL
UNION SELECT '20--' AS y FROM DUAL
UNION SELECT '09' AS y FROM DUAL
UNION SELECT '11' AS y FROM DUAL
UNION SELECT '95' AS y FROM DUAL
) s;
EXCEPTION
WHEN INVALID_NUMBER THEN NULL;
END;
我现在收到一个不同的错误 ORA-06550: line 2, column 3: PLS-00428: an INTO clause is expected in this SELECT statement
。
SQL中没有异常处理;您需要创建一个 PL/SQL 块来处理异常(请注意,我将您的 UNION
更改为 UNION ALL
):
BEGIN
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(s.y) AS p
FROM src s;
EXCEPTION
WHEN INVALID_NUMBER THEN NULL;
END;
/
但是您可以使用正则表达式来执行 "safe" 数字转换,而不是使用 PL/SQL 块:
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(REGEXP_SUBSTR(s.y, '^\d+'))
FROM src s;
以上会将值 20--
转换为 20
,这可能不是您想要的 - 在这种情况下,请尝试使用此模式 ^\d+$
:
WITH src AS (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
)
SELECT s.y, TO_NUMBER(REGEXP_SUBSTR(s.y, '^\d+$'))
FROM src s;
希望对您有所帮助。
是的,确实如此,但有内联函数 (Oracle 12c) 之类的解决方法:
WITH FUNCTION safe_to_NUMBER(input IN VARCHAR2)
RETURN NUMBER IS
i NUMBER;
BEGIN
i:= TO_NUMBER(input);
RETURN i;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
SELECT sub.y, safe_to_NUMBER(sub.y)
FROM (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
) sub;
结果:
Y SAFE_TO_NUMBER(SUB.Y)
---- ---------------------
2000 2000
1991 1991
20--
09 9
11 11
95 95
6 rows selected.
我当然不会写这样的生产代码:)
正确方法(DEFAULT NULL ON CONVERSION ERROR
- 从 Oracle12cR2 开始可用):
SELECT sub.y, TO_NUMBER(sub.y DEFAULT NULL ON CONVERSION ERROR) AS y
FROM (
SELECT '2000' AS y FROM DUAL UNION ALL
SELECT '1991' AS y FROM DUAL UNION ALL
SELECT '20--' AS y FROM DUAL UNION ALL
SELECT '09' AS y FROM DUAL UNION ALL
SELECT '11' AS y FROM DUAL UNION ALL
SELECT '95' AS y FROM DUAL
) sub;
输出:
Y Y
---- ----------
2000 2000
1991 1991
20--
09 9
11 11
95 95
6 rows selected.