views:

161

answers:

7

I have this database which contains a varchar.

I want to know which records holds numeric values. I tried REGEXP_COUNT and other but I'm running on 9i and I think this is for 10g >

How can I achieve this?

I tried:

 select to_number( my_column ) from my_table

But it doesn't work, because well not all of them are numeric.

EDIT

Background.

This table contains employee id's, all of which are numeric ( read 1234 or 24523 or 6655 )

The in the initial database load, when the employee id was unknown instead of using something like -1 they entered texts like:

NA, N/A, NONE, UNK, UNKNOW, TEST, EXTERNAL, WITHOUT_ID

Really the main fault is, that column is varchar and not number as it should.

Now, what I try to do, is to get ll the records that are not numeric ( that don't contain an employee id ) but since that db is 9i, I could not use RegExp

+4  A: 

I am afraid you'll have to write your own isnumber function, and then use it, something like this (untested) found in this thread, should work.

 DECLARE FUNCTION isNumber(p_text IN VARCHAR2) RETURN NUMBER IS
 v_dummy NUMBER;
 not_number EXCEPTION;
 PRAGMA EXCEPTION_INIT(-, not_number);
 BEGIN
     v_dummy := TO_NUMBER(p_text);
     RETURN 1;
   EXCEPTION
   WHEN not_number THEN RETURN 0;
 END is_number;

After that you could use a decode function combined with your isnumber function to get the results you need.

pedromarce
Good, but the function cannot return BOOLEAN if it is to be used in SQL - change it to return NUMBER (0/1) or VARCHAR2 (Y/N)
Tony Andrews
+1 :) .........
OscarRyz
Much better as NUMBER indeed :)
pedromarce
+1, upvote for the code, but I'm tempted to downvote for the reference to a site that makes you register to see content :-| Better to reference asktom: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:15321803936685
DCookie
A: 

I manage to work around like this:

select my_column
from my_table
where my_column not like '%1%'
and my_column not like '%2%'
and my_column not like '%3%'
and my_column not like '%4%'
and my_column not like '%5%'
and my_column not like '%6%'
and my_column not like '%7%'
and my_column not like '%8%'
and my_column not like '%9%'
and my_column not like '%0%'

Dirty, but it works. ;)

OscarRyz
If this query is trying to get rows that don't contain a number then it fails if the value has a number somewhere within it, try it with "mydoghas3legs".
Paul James
Ahh nope, actually I tried to get all the non numeric values. ... I'll update my original question
OscarRyz
+2  A: 

Just another pure SQL workaround:

select my_column
  from my_table
 where translate(my_column,'x0123456789','x') is null;
egorius
This only works for integers. But before you rush to add a decimal point to the TRANSLATE() list remember that IP addresses *are not numbers* so 123.456.789.255 must fail your test.
APC
Sure, that's why "workaround." But sometimes it can help and it's simple.
egorius
A: 

Depends on what you count as 'numeric'. Do you allow negative numbers, decimals or just integers, or scientific notation (eg '1e3'). Are leading zeroes allowed ?

If you just want positive integer values, try

where translate(col,' 1234567890','0') is null
Gary
A: 

Yet another approach, here's a function I wrote some time ago:

CREATE OR REPLACE function string_is_numeric
 (p_string_in in varchar2)
return boolean is
begin
  for i in 1..length(p_string_in) loop
    if substr(p_string_in, i, 1) not in ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') then
      return false;
    end if;
  end loop;
  return true;
end;
/

As pointed out in pedromarce's answer, you might need to change that from a boolean return to number or varchar2 to better suit your needs.

AndyDan
Another one which fails to handle decimal points. Also one where the performance is likely to be quite poor.
APC
Adding a decimal point to the function is so simple as to not warrant a comment. I never claimed this function was perfect, but it suits my needs and might do the same for the OP. Performance would only be a significant issue if this was called frequently, and/or for very large strings.
AndyDan
+1  A: 

Try this

CREATE OR REPLACE PACKAGE value_tests
AS
   FUNCTION get_number( pv_value IN VARCHAR2 ) RETURN NUMBER;
END;
/

CREATE OR REPLACE PACKAGE BODY value_tests
AS
   FUNCTION get_number( pv_value IN VARCHAR2 ) RETURN NUMBER
   IS
      converted_number NUMBER;

      invalid_number EXCEPTION;       
      PRAGMA EXCEPTION_INIT( invalid_number, -01722 );

      value_error EXCEPTION;       
      PRAGMA EXCEPTION_INIT( value_error, -06502 );

   BEGIN
      <<try_conversion>>
      BEGIN
         converted_number := TO_NUMBER( pv_value );
      EXCEPTION
         WHEN invalid_number OR value_error
         THEN 
            converted_number := NULL;
      END try_conversion;

      RETURN converted_number;
   END get_number;
END;
/

Running it on this...

select my_column
     , value_tests.get_number( my_column ) my_column_num
  from (           select 'mydoghas3legs' my_column from dual 
         union all select '27.5' my_column from dual
         union all select '27.50.5' my_column from dual
       )

returns

MY_COLUMN     MY_COLUMN_NUM
------------- -------------
mydoghas3legs
27.5                   27.5
27.50.5
Paul James
A: 

I do not like using exceptions in normal code but this seems to be the best and safest aproach:

CREATE OR REPLACE FUNCTION "IS_NUMBER" (pX in varchar2) return integer is
       n number;
begin
     n:=to_number(pX);
     return 1;
     exception
              when others then
                   return 0;
end;
borjab