Как я могу определить, является ли строка числовой в SQL?
В запросе SQL на Oracle 10g мне нужно определить, является ли строка числовой или нет. Как я могу это сделать?
7 ответов
Вы можете использовать REGEXP_LIKE:
SELECT 1 FROM DUAL
WHERE REGEXP_LIKE('23.9', '^\d+(\.\d+)?$', '')
Вы можете попробовать это:
SELECT LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) FROM DUAL
где string1 - это то, что вы оцениваете. Он вернет ноль, если числовой. Смотрите здесь для дальнейшего уточнения
У меня нет доступа к экземпляру 10G для тестирования, но это работает в 9i:
СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ФУНКЦИЮ is_numeric (p_val VARCHAR2) Возвратный номер ЯВЛЯЕТСЯ v_val NUMBER; НАЧАТЬ НАЧАТЬ ЕСЛИ p_val = NULL ИЛИ TRIM (p_val) = '' ЗАТЕМ ВОЗВРАТ 0; END IF; ВЫБЕРИТЕ TO_NUMBER (p_val) INTO v_val ОТ ДВОЙНОГО; ВОЗВРАТ 1; ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ЗАТЕМ ВОЗВРАТ 0; КОНЕЦ; КОНЕЦ; SELECT is_numeric ('333.5') is_numeric ОТ ДВОЙНОГО;
Я предположил, что вы хотите, чтобы значения null /empties рассматривались как FALSE.
Как указал Том Кайт в http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:7466996200346537833, если вы используете встроенный TO_NUMBER
в пользовательской функции может потребоваться дополнительная хитрость, чтобы она заработала.
FUNCTION is_number(x IN VARCHAR2)
RETURN NUMBER
IS
PROCEDURE check_number (y IN NUMBER)
IS
BEGIN
NULL;
END;
BEGIN
PRAGMA INLINE(check_number, 'No');
check_number(TO_NUMBER(x);
RETURN 1;
EXCEPTION
WHEN INVALID_NUMBER
THEN RETURN 0;
END is_number;
Проблема в том, что оптимизирующий компилятор может распознать, что результат TO_NUMBER
не используется нигде и оптимизировать его подальше.
Том говорит (его пример был о датах, а не числах):
отключение функции inlining заставит его выполнить вызов check_date, который должен быть выполнен как вызов функции, - чтобы сделать так, чтобы DATE был помещен в стек вызовов. В этом случае оптимизирующий компилятор не сможет удалить вызов to_date. Если вызов to_date, необходимый для вызова check_date, по какой-либо причине завершается неудачно, мы знаем, что строковый ввод не был конвертируемым в этом формате даты.
Вот метод определения числа, которое может быть частью простого запроса, без создания функции. Учет встроенных пробелов, +- не первый символ или вторая десятичная точка.
var v_test varchar2(20);
EXEC :v_test := ' -24.9 ';
select
(case when trim(:v_test) is null then 'N' ELSE -- only banks, or null
(case when instr(trim(:v_test),'+',2,1) > 0 then 'N' ELSE -- + sign not first char
(case when instr(trim(:v_test),'-',2,1) > 0 then 'N' ELSE -- - sign not first char
(case when instr(trim(:v_test),' ',1,1) > 0 then 'N' ELSE -- internal spaces
(case when instr(trim(:v_test),'.',1,2) > 0 then 'N' ELSE -- second decimal point
(case when LENGTH(TRIM(TRANSLATE(:v_test, ' +-.0123456789',' '))) is not null then 'N' ELSE -- only valid numeric charcters.
'Y'
END)END)END)END)END)END) as is_numeric
from dual;
Для целых чисел вы можете использовать ниже. Первый перевод изменяет пробелы на символы, а второй меняет числа на пробелы. Обрезка вернет ноль, если существуют только числа.
TRIM(TRANSLATE(TRANSLATE(TRIM('1 2 3d 4'), ' ','@'),'0123456789',' ')) is null
Я обнаружил, что решение
LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) is null
позволяет встроенные пробелы... он принимает "123 45 6789", который для моей цели не является числом.
Другой уровень обрезки / перевода исправляет это. Следующее обнаружит строковое поле, содержащее последовательные цифры с начальными или конечными пробелами, так что to_number(trim(string1)) не потерпит неудачу
LENGTH(TRIM(TRANSLATE(translate(trim(string1),' ','X'), '0123456789', ' '))) is null