Обработка исключений в Oracle - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь разобрать годы, введенные в виде строк (, пожалуйста, не начинайте, это то, что ).Однако есть введенные годы, которые не могут быть проанализированы 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.

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

В SQL нет обработки исключений;

Да, это так, но есть обходной путь, подобный встроенной функции (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. 
0 голосов
/ 06 июня 2018

В SQL нет обработки исключений;вам нужно создать блок PL / SQL для обработки исключения (обратите внимание, что я изменил ваши UNION s на 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;
/

Но вместо того, чтобы использовать блок 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;

Надеюсь, это поможет.

...