Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Dee.

Asked: November 22, 2005 - 11:38 am UTC

Last updated: March 15, 2006 - 5:09 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

In a table there is a column called description (char(50)). Some of the values have numbers at the end. I need to remove them all at the end only and keep everything else. There are cases where there are numbers in the beginning or middle. There is only about 100 rows in this table. Of course, the modified description column is the one I need to see.

I really don't know how to do this.

Description Modified Description
2003 HOL PERM FIX 04069510367 2003 HOL PERM FIX
2003 HOL STD LG FIX 040695103327 2003 HOL STD LG FIX
2004 HOL FL LG FIX 2004 HOL FL LG FIX
HOL 2004 SM FIX HOL 2004 SM FIX




and Tom said...

is there always a space there? if so,


ops$tkyte@ORA10GR2> select x,
2 case when replace( trim(translate( substr( x, instr(rtrim(x),' ',-1)+1 ), '0123456789','0000000000')), '0', '' ) is null
3 then substr( x, 1, instr(rtrim(x),' ',-1) )
4 else x
5 end y
6 from t;



the substr( x, instr(rtrim(x),' ',-1)+1 ) gets the last "word"

the translate turns all digits into 0's

the replace will NULL out a string of entirely 0's after the translate

if that is null, return the substr
else return the entire string.

Rating

  (15 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Removing numbers at end of field

Dee, November 22, 2005 - 4:40 pm UTC

Thanks for the quick reply Tom. The answer to you questions is I found it to be inconsistent regarding spaces at the end of the field or not.

I had basically used a very similar sql statement but couldn't get it to work, it kept erroring out.
(select case when TO_NUMBER(translate(substr(trim(d), instr(trim(d),' ',-1) + 1) , '0123456789','0000000000')) = 0 then trim(substr(trim(d), 1, instr(trim(d),' ',-1))) else trim(d) end
from a)


However, I used yours and it ran but the data looks exactly as if I did a select *.

Tom Kyte
November 23, 2005 - 9:08 am UTC

are you sure?

ops$tkyte@ORA10GR2> select * from t;

X
--------------------------------------------------
2003 HOL PERM FIX         04069510367
2003 HOL STD LG FIX   040695103327
2004 HOL FL LG FIX
HOL 2004 SM FIX

ops$tkyte@ORA10GR2> select case when replace( trim(translate( substr( x, instr(rtrim(x),' ',-1)+1 ), '0123456789','0000000000')), '0', '' ) is null
  2              then substr( x, 1, instr(rtrim(x),' ',-1) )
  3              else x
  4          end y
  5  from t;

Y
--------------------------------------------------
2003 HOL PERM FIX
2003 HOL STD LG FIX
2004 HOL FL LG FIX
HOL 2004 SM FIX


 

Another way

Bob B, November 22, 2005 - 5:02 pm UTC

The following sql removes numbers starting at the end of the string and working back to the first non-number.

SELECT
SUBSTR( x, 1, LENGTH( RTRIM( TRANSLATE( x, '0123456789', '0000000000' ), '0' ) ) )
FROM t


The following sql removes numbers and whitespace starting at the end of the string and working back to the first non-number/non-whitespace character.

SELECT
SUBSTR( x, 1, LENGTH( RTRIM( TRANSLATE( x, '0123456789' ) ) ) )
FROM t

Tom Kyte
November 23, 2005 - 9:10 am UTC

char(50) :)

ops$tkyte@ORA10GR2> SELECT
  2    SUBSTR( x, 1, LENGTH( RTRIM( TRANSLATE( x, '0123456789', '0000000000' ), '0' )
  3  ) )
  4  FROM t
  5  /

SUBSTR(X,1,LENGTH(RTRIM(TRANSLATE(X,'0123456789','
--------------------------------------------------
2003 HOL PERM FIX         04069510367
2003 HOL STD LG FIX   040695103327
2004 HOL FL LG FIX
HOL 2004 SM FIX


but a trim....


  1  SELECT
  2    SUBSTR( x, 1, LENGTH( RTRIM( TRANSLATE( trim(x), '0123456789', '0000000000' ), '0' )
  3  ) )
  4* FROM t
ops$tkyte@ORA10GR2> /

SUBSTR(X,1,LENGTH(RTRIM(TRANSLATE(TRIM(X),'0123456
--------------------------------------------------
2003 HOL PERM FIX
2003 HOL STD LG FIX
2004 HOL FL LG FIX
HOL 2004 SM FIX



 

Why not this?

Mark Wooldridge, November 22, 2005 - 5:53 pm UTC

  1  select rtrim('2003 HOL PERM FIX         04069510367   ', '0123456789 ')
  2* from dual
SQL> /

RTRIM('2003HOLPER
-----------------
2003 HOL PERM FIX

Will trim all whitespace and any number from the right end of the string.

Unless the need is to remove a block of numbers at the end.
ex:HOL PERM FIX         04069510367 1235
results in HOL PERM FIX         04069510367

In which case something like this might work
  1  select rtrim(rtrim('2003 HOL PERM FIX         04069510367 1234', ' '), '0123456789')
  2* from dual
SQL> /

RTRIM(RTRIM('2003HOLPERMFIX04069510367
--------------------------------------
2003 HOL PERM FIX         04069510367

remove any trialing spaces and then trim the numbers 

Tom Kyte
November 23, 2005 - 9:17 am UTC

very nice :)


always forget rtrim/ltrim take a "set" of characters.

Nice Stuff

Soma, November 23, 2005 - 6:19 am UTC


Learn something new everyday ...

Bob B, November 23, 2005 - 10:08 am UTC

Trims takes character sets - sweet. Much easier to read it that way.

Learnt Something New Today

Mac, November 23, 2005 - 10:18 am UTC

Thanks Mark for pointing that out. One nitpick:
Your second (nested RTRIMs) statement could be simplified as:

>>1 select rtrim('2003 HOL PERM FIX 04069510367 1234','0123456789')from dual;

RTRIM('2003HOLPERMFIX040695103671234',
--------------------------------------
2003 HOL PERM FIX 04069510367

1 row selected.

Dee, November 23, 2005 - 2:32 pm UTC

Most of all thanks for the fast reply. I was amazed.
Thanks it is working fine.

regexp_replace

Kirill, November 23, 2005 - 3:46 pm UTC

select
regexp_replace(x,'[[:digit:]]+$','')
from t;

...or
regexp_replace(x,'\s+[[:digit:]]+$','')

to get rid of the spaces before the number


Second option

Mark Wooldridge, November 23, 2005 - 6:07 pm UTC

Mac,

I added the inner rtrim to remove any potential whitespace at the end but since the data was in a varchar2 any trialing whitespace would probably not exist.  Just like to cover any potential problems.  I guess there could be other non printable characters at the end also besides whitespace.

Just in case someone had something like this
SQL> create table msw0 (c1 varchar2(10))
  2  /

Table created.

SQL> insert into msw0 values('hello'||chr(32))
  2  /

1 row created.

SQL> select length(c1) from msw0
  2  /

LENGTH(C1)
----------
         6

  1  select c1||'*'
  2* from msw0
SQL> /

C1||'*'
-----------
hello *

 

Should have..

Mark Wooldridge, November 23, 2005 - 6:15 pm UTC

read more of the thread.  Give that the data was in a char(50) column the inner rtrim is necessary.

SQL> create table msw0
  2  (c1 char(50))
  3  /

Table created.

SQL> insert into msw0 values('HOL PERM FIX         04069510367 1235
  2  
SQL> 
SQL> ed
Wrote file afiedt.buf

  1* insert into msw0 values('HOL PERM FIX         04069510367 1235')
SQL> /

1 row created.

SQL> select rtrim(c1, '0123456789')
  2  from msw0
  3  /

RTRIM(C1,'0123456789')
--------------------------------------------------
HOL PERM FIX         04069510367 1235

SQL> ed
Wrote file afiedt.buf

  1  select rtrim(rtrim(c1, ' '), '0123456789')
  2* from msw0
SQL> /

RTRIM(RTRIM(C1,''),'0123456789')
--------------------------------------------------
HOL PERM FIX         04069510367 

Tom Kyte
November 23, 2005 - 8:10 pm UTC

no sweat, you get a freebie for coming up with the easy answer :)

Too easy to believe...

Dee, December 01, 2005 - 12:50 pm UTC

This was great!!!
I simply am amazed at how easy this ended up being.
Just knowing rtrim took away character sets is worth never forgetting. WOW!!

is this the same with character??

A reader, January 01, 2006 - 4:18 am UTC

Hi,

I have this table.

select * from pcbq2;

YEAR MONTH_YEAR PROJ_NAME ERROR_TYPE
----- ---------- --------- ----------------------
2004 06-04 NEO Short/Open :
2004 06-04 NEO Drill table/data :
2004 06-04 NEO Milling table/data :
2004 06-04 NEO All Gerber file :

4 rows selected.

I want to remove ':' from error_type column. How can i do that? Just went tru all the reviews and finally came out with this.

select case when
replace( trim(translate( substr( error_type, instr(rtrim(error_type),'',-1)+1 ), ':','')), '0', '' ) is null
then substr( error_type, 1, instr(rtrim(error_type),'',-1) )
else error_type
end error_type
from pcbq2;

But unfortunately nothing came out. I think I misunderstood the concept.Can somebody please help me out?

Thanks for your help in advance.


Tom Kyte
January 01, 2006 - 11:06 am UTC

why not just


replace( error_type, ':', '' )

??

u r great!

A reader, January 01, 2006 - 9:57 pm UTC

yeah, i should think of that. You are totally awesome!!

rtrim for a character string with '_'

Naresh, March 15, 2006 - 10:02 am UTC

Hi Tom,

Slightly different question (not trimming number but a string) -

I want to remove trailing pattern '_tas_d' from some strings.

In the below statements, why does the additional t vanish from 'account_tas_d' and 'agreement_tas_d':

SQL> select rtrim('address_name_tas_d', '_tas_d') from dual;

RTRIM('ADDRE
------------
address_name

SQL> select rtrim('account_tas_d', '_tas_d') from dual;

RTRIM(
------
accoun

SQL> select rtrim('agreement_tas_d', '_tas_d') from dual;

RTRIM('A
--------
agreemen

Thanks,
Naresh. 

Tom Kyte
March 15, 2006 - 5:09 pm UTC

rtrim looks at the SET of characters "_tas_d"

ops$tkyte@ORA10GR2> select rtrim('address_name_tas_d', '_tas_d'),
  2         rtrim('address_name_tas_d', 'd_sat' )
  3   from dual;

RTRIM('ADDRE RTRIM('ADDRE
------------ ------------
address_name address_name



if you want to remove the trailing STRING _tas_d, you might use:

case when COL like '%\_tas\_d' escape '\'
     then substr( COL, 1, length(col)-6)
     else COL
 end 

Thank You!

Naresh, March 17, 2006 - 7:23 am UTC

Thank You Tom, the "case" works.

I encountered the escape syntax for the first time - very useful to know this.