проверьте, является ли функция" это число " в Oracle
Я пытаюсь проверить, является ли значение из столбца в запросе oracle (10g) числом, чтобы сравнить его. Что-то вроде:
select case when ( is_number(myTable.id) and (myTable.id >0) )
then 'Is a number greater than 0'
else 'it is not a number'
end as valuetype
from table myTable
есть идеи, как это проверить?
15 ответов
предполагая, что столбец ID в myTable
не объявляется как число (что кажется странным выбором и, вероятно, будет проблематичным), вы можете написать функцию, которая пытается преобразовать (предположительно VARCHAR2) ID в число, ловит исключение и возвращает " Y " или "N". Что-то вроде
CREATE OR REPLACE FUNCTION is_number( p_str IN VARCHAR2 )
RETURN VARCHAR2 DETERMINISTIC PARALLEL_ENABLE
IS
l_num NUMBER;
BEGIN
l_num := to_number( p_str );
RETURN 'Y';
EXCEPTION
WHEN value_error THEN
RETURN 'N';
END is_number;
затем вы можете вставлять в запрос, т. е.
SELECT (CASE WHEN is_number( myTable.id ) = 'Y' AND myTable.id > 0
THEN 'Number > 0'
ELSE 'Something else'
END) some_alias
FROM myTable
обратите внимание, что хотя PL/SQL имеет логический тип данных, SQL этого не делает. Поэтому, пока вы можете объявить функция, возвращающая логическое значение, не может использоваться в SQL-запросе.
одна дополнительная идея, упомянул здесь - использовать регулярное выражение для проверки:
SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^[[:digit:]]+$');
хорошая часть - вам не нужна отдельная функция PL/SQL. Потенциально проблематичным является то, что регулярное выражение может быть не самым эффективным методом для большого количества строк.
Saish с помощью REGEXP_LIKE
- правильная идея, но не поддерживает плавающие числа. Этот будет ...
возвращаемые числовые значения
SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
возвращаемые значения не числовое
SELECT foo
FROM bar
WHERE NOT REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
вы можете проверить свои регулярные выражения сами, пока ваше сердце не будет удовлетворено в http://regexpal.com/ (но убедитесь, что вы установили флажок матч в перерывах для этого).
вы можете использовать функцию регулярного выражения "regexp_like" в ORACLE (10g), как показано ниже:
select case
when regexp_like(myTable.id, '[[:digit:]]') then
case
when myTable.id > 0 then
'Is a number greater than 0'
else
'Is a number less than or equal to 0'
end else 'it is not a number' end as valuetype
from table myTable
это потенциальный дубликат Поиск строк, которые не содержат числовых данных в Oracle. См. также: как определить, является ли строка числовой в SQL?.
вот решение, основанное на Майкла Дарранта это работает для целых чисел.
SELECT foo
FROM bar
WHERE DECODE(TRIM(TRANSLATE(your_number,'0123456789',' ')), NULL, 'number','contains char') = 'number'
Эдриан Карнейро опубликовано решение, которое работает для дроби и другие. Однако, как отметил Джастин Кейв, это будет неправильно классифицировать строки, такие как "123.45.23.234" или "131+234".
SELECT foo
FROM bar
WHERE DECODE(TRIM(TRANSLATE(your_number,'+-.0123456789',' ')), NULL, 'number','contains char') = 'number'
Если вам нужно решение без PL / SQL или REGEXP_LIKE, это может помочь.
Я против использования when others
поэтому я бы использовал (возвращая "логическое целое число" из-за того, что SQL не поддерживает логические значения)
create or replace function is_number(param in varchar2) return integer
is
ret number;
begin
ret := to_number(param);
return 1; --true
exception
when invalid_number then return 0;
end;
в вызове SQL вы бы использовали что-то вроде
select case when ( is_number(myTable.id)=1 and (myTable.id >'0') )
then 'Is a number greater than 0'
else 'it is not a number or is not greater than 0'
end as valuetype
from table myTable
Как определяется столбец? Если его поле varchar, то его не число (или хранится как один). Oracle может выполнить преобразование для вас (например, выберите * из someTable, где charField = 0), но он будет возвращать только строки, где преобразование имеет значение true и возможно. Это также далеко от идеальной ситуации.
Итак, если вы хотите сделать сравнение чисел и рассматривать этот столбец как число, возможно, его следует определить как число?
что сказал, Вот что вы могли бы сделать:
create or replace function myToNumber(i_val in varchar2) return number is
v_num number;
begin
begin
select to_number(i_val) into v_num from dual;
exception
when invalid_number then
return null;
end;
return v_num;
end;
вы также можете включить другие параметры, которые имеет обычный to_number. Используйте как так:
select * from someTable where myToNumber(someCharField) > 0;
Он не будет возвращать строки, которые Oracle видит как недопустимое число.
Ура.
CREATE OR REPLACE FUNCTION is_number(N IN VARCHAR2) RETURN NUMBER IS
BEGIN
RETURN CASE regexp_like(N,'^[\+\-]?[0-9]*\.?[0-9]+$') WHEN TRUE THEN 1 ELSE 0 END;
END is_number;
обратите внимание, что он не будет 45e4 как число, но вы всегда можете изменить регулярное выражение, чтобы выполнить обратное.
@JustinCave-замена" when value_error "на" when others " является хорошим уточнением вашего подхода выше. Эта небольшая дополнительная настройка, хотя концептуально то же самое, удаляет требование определения и последующего выделения памяти для вашей переменной l_num:
function validNumber(vSomeValue IN varchar2)
return varchar2 DETERMINISTIC PARALLEL_ENABLE
is
begin
return case when abs(vSomeValue) >= 0 then 'T' end;
exception
when value_error then
return 'F';
end;
просто Примечание также для тех, кто предпочитает эмулировать логику формата Oracle number с использованием подхода" рискованное " регулярное выражение, пожалуйста, не забудьте рассмотреть NLS_NUMERIC_CHARACTERS и NLS_TERRITORY.
Это мой запрос, чтобы найти все те, которые не являются числом:
Select myVarcharField
From myTable
where not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\.\d+)?$', '')
and not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\,\d+)?$', '');
в моей области я . и, к сожалению, десятичные числа так должны были учитывать это, иначе вам нужно только одно ограничение.
ну, вы можете создать функцию is_number для вызова, чтобы ваш код работал.
create or replace function is_number(param varchar2) return boolean
as
ret number;
begin
ret := to_number(param);
return true;
exception
when others then return false;
end;
EDIT: пожалуйста, отложите ответ Джастина. Забыл эту маленькую деталь для чистого вызова SQL....
функция для мобильного номера длиной 10 цифр и начиная с 9,8,7 с помощью regexp
create or replace FUNCTION VALIDATE_MOBILE_NUMBER
(
"MOBILE_NUMBER" IN varchar2
)
RETURN varchar2
IS
v_result varchar2(10);
BEGIN
CASE
WHEN length(MOBILE_NUMBER) = 10
AND MOBILE_NUMBER IS NOT NULL
AND REGEXP_LIKE(MOBILE_NUMBER, '^[0-9]+$')
AND MOBILE_NUMBER Like '9%' OR MOBILE_NUMBER Like '8%' OR MOBILE_NUMBER Like '7%'
then
v_result := 'valid';
RETURN v_result;
else
v_result := 'invalid';
RETURN v_result;
end case;
END;
Я считаю, что следующее решение (на основе подхода regexp_like выше) является оптимальным:
function isInteger(vYourValue IN varchar2)
return varchar2
is
begin
return case REGEXP_INSTR(vYourValue,'^[[:digit:]]+$') when 0 then 'F' else 'T' end;
end;
почему я говорю это?
проверенное числовое подмножество можно изменить по желанию, соответствующим образом изменив регулярное выражение.
его можно использовать в SQL ie select isInteger (myCol) из mytable; поскольку он возвращает " T " из " F " вместо boolean.
Он может использоваться изначально в PL / sql ie. если isInteger (vMyValue) = 'T' тогда ....
он удовлетворяет утверждению чистоты WNDS,wnps.
он не полагается на, на мой взгляд, слишком широкий спектр подхода "когда другие" для определения результата.
обратите внимание, что regexp или функциональные подходы в несколько раз медленнее, чем простое условие sql.
таким образом, некоторые эвристические обходные пути с ограниченной применимостью делают sence для огромных сканирований.
есть решение для случаев, когда вы точно знаете, что нечисловые значения будут содержать букв:
select case when upper(dummy)=lower(dummy) then '~numeric' else '~alpabetic' end from dual
и если вы знаете, что какая-то буква всегда будет присутствовать в нечисловых случаи:
select case when instr(dummy, 'X')>0 then '~alpabetic' else '~numeric' end from dual
когда числовые случаи всегда будут содержать ноль:
select case when instr(dummy, '0')=0 then '~alpabetic' else '~numeric' end from dual
если условие равно null, то это число
IF(rtrim(P_COD_LEGACY, '0123456789') IS NULL) THEN
return 1;
ELSE
return 0;
END IF;