Как я могу определить, является ли строка числовой в SQL? - PullRequest
13 голосов
/ 14 апреля 2011

В запросе SQL в Oracle 10g мне нужно определить, является ли строка числовой или нет.Как я могу это сделать?

Ответы [ 7 ]

27 голосов
/ 14 апреля 2011

Вы можете использовать REGEXP_LIKE:

SELECT 1 FROM DUAL
WHERE REGEXP_LIKE('23.9', '^\d+(\.\d+)?$', '') 
5 голосов
/ 14 апреля 2011

Вы можете попробовать это:

SELECT LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) FROM DUAL

, где string1 - это то, что вы оцениваете.Он вернет ноль, если числовой.Смотрите здесь для дальнейших разъяснений

2 голосов
/ 04 ноября 2013

Как указал Том Кайт в 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 должен быть выполнен как вызов функции - сделать так, чтобы ДАТА должна быть помещена в стек вызовов. Там нет шансов для оптимизирующий компилятор для удаления вызова to_date в этом случае. Если вызов to_date необходим для вызова check_date не удастся для любого причина, мы знаем, что строковый ввод не был конвертируемым к этой дате формат.

2 голосов
/ 14 апреля 2011

У меня нет доступа к экземпляру 10G для тестирования, но это работает в 9i:


CREATE OR REPLACE FUNCTION is_numeric (p_val VARCHAR2)
   RETURN NUMBER
IS
v_val   NUMBER;
BEGIN
   BEGIN
      IF p_val IS NULL OR TRIM (p_val) = ''
      THEN
         RETURN 0;
      END IF;

      SELECT TO_NUMBER (p_val)
        INTO v_val
        FROM DUAL;

      RETURN 1;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN 0;
   END;
END;


SELECT is_numeric ('333.5') is_numeric
  FROM DUAL;

Я предполагаю, что вы хотите, чтобы значения null / empties рассматривались как FALSE.

0 голосов
/ 25 сентября 2015

Вот метод определения числа, которое может быть частью простого запроса, без создания функции. Учет встроенных пробелов, + - не первый символ или вторая десятичная точка.

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;
0 голосов
/ 21 января 2015

Для целых чисел вы можете использовать ниже.Первый перевод изменяет пробелы на символы, а второй меняет числа на пробелы.Обрезка вернет ноль, если существуют только числа.

TRIM(TRANSLATE(TRANSLATE(TRIM('1 2 3d 4'), ' ','@'),'0123456789',' ')) is null
0 голосов
/ 19 августа 2014

Я обнаружил, что решение

LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) is null

допускает встроенные пробелы ... оно принимает "123 45 6789", которое для моей цели не является числом.

Другой уровень обрезки / перевода исправляет это.Следующее обнаружит строковое поле, содержащее последовательные цифры с начальными или конечными пробелами, так что to_number (trim (string1)) не завершится с ошибкой

LENGTH(TRIM(TRANSLATE(translate(trim(string1),' ','X'), '0123456789', ' '))) is null
...