Хотя @Dave прав насчет того вопроса, который вы задали, я думаю, что вы пытаетесь достичь, отличается от того, что вы делаете. Как написано, блок PL / SQL будет оценивать значения только до тех пор, пока не достигнет первого нечислового значения. Если вы хотите, чтобы все значения были оценены, вам понадобится что-то вроде этого:
BEGIN
FOR rec IN (SELECT '10' house_nr FROM DUAL
UNION ALL
SELECT '10a' house_nr FROM DUAL
UNION ALL
SELECT '11' house_nr FROM DUAL) LOOP
error_fl := FALSE;
BEGIN
number_correct := TO_NUMBER(rec.house_nr);
EXCEPTION
WHEN VALUE_ERROR THEN
error_fl := TRUE;
WHEN OTHERS THEN
RAISE;
END;
IF error_fl THEN
DBMS_OUTPUT.put_line('incorrect: ' || rec.house_nr);
ELSE
DBMS_OUTPUT.put_line('correct: ' || rec.house_nr);
END IF;
END LOOP;
END;
Переместив обработку исключений внутрь цикла, мы можем продолжить обработку после возникновения ошибки. Кроме того, эта версия возвращает «неправильное» сообщение только в том случае, если возникшая ошибка фактически является ошибкой преобразования, а не неожиданной ошибкой. Когда вы пишете обработку ошибок для конкретных условий, подобных этой, важно быть максимально точным.
Как указывает @Stephen, регулярное выражение, как правило, быстрее, чем процедуры или функции PL / SQL, и один оператор SQL обычно лучше, чем процедурный цикл. Однако функции регулярных выражений можно использовать только в предложениях where
, поэтому, если вы хотите просмотреть результаты для всех значений, вам потребуется дважды запросить таблицу:
WITH test_num as (SELECT '10' house_nr FROM DUAL
UNION ALL
SELECT '10a' house_nr FROM DUAL
UNION ALL
SELECT '11' house_nr FROM DUAL)
SELECT 'correct' AS status, a.*
FROM test_num a
WHERE REGEXP_LIKE(t1, '[^[:digit:]]')
UNION ALL
SELECT 'incorrect', a.*
FROM test_num a
WHERE NOT REGEXP_LIKE(t1, '[^[:digit:]]');
Если вы не знакомы с регулярным выражением или не можете найти подходящее выражение, вы все равно можете сделать это в одном выражении SQL, создав собственную функцию:
CREATE OR REPLACE FUNCTION is_num(p_string VARCHAR2)
RETURN NUMBER
DETERMINISTIC IS
v_test NUMBER;
BEGIN
v_test := p_string;
RETURN 1;
EXCEPTION
WHEN VALUE_ERROR THEN
RETURN 0;
WHEN OTHERS THEN
RAISE;
END;
WITH test_num as (SELECT '10' house_nr FROM DUAL
UNION ALL
SELECT '10a' house_nr FROM DUAL
UNION ALL
SELECT '11' house_nr FROM DUAL)
SELECT CASE is_num(t1) WHEN 0 THEN 'correct' ELSE 'incorrect' END AS status, a.*
FROM test_num a;
Это не так быстро, как использование регулярных выражений в большинстве случаев, но у него есть одно преимущество: основанные на функциях индексы общеизвестно привередливы к функциям регулярных выражений, но у них не должно быть проблем с такой функцией. Не похоже, что вам нужен индекс для этого конкретного запроса, но об этом следует помнить.