Skip to Main Content
  • Questions
  • String concat with ASCII function with length>39 returns 00

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, sujatha.

Asked: October 14, 2015 - 11:16 am UTC

Last updated: October 14, 2015 - 1:53 pm UTC

Version: 11.2.0.3

Viewed 1000+ times

You Asked

Hi Tom,

I have a function which converts input string to a number and returns it as varchar.

string Exp : MALT011000012345MTLCAST001SMT84

<code>  FUNCTION translate_alpha (
    p_str                                VARCHAR2
  )
    RETURN VARCHAR2
  AS
    l_str                         VARCHAR2 (100) := UPPER (p_str);
    l_out_str                     VARCHAR2 (100) := '';
    l_str_tok                     CHAR (1);
    l_index                       BINARY_INTEGER;
  BEGIN
    register_proc ('validateIBAN.translate_alpha', 'p_str = ' || p_str);
    g_comments                 := 'tokenizer';

    FOR l_index IN 1 .. LENGTH (l_str)
    LOOP
      l_str_tok                  := SUBSTR (l_str,
                                            l_index,
                                            1
                                           );

      IF l_str_tok IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
      THEN
        l_out_str                  := l_out_str || l_str_tok;
      ELSE
 <code>       l_out_str                  := l_out_str || ASCII (l_str_tok) - 55;

END IF;
END LOOP;

RETURN l_out_str;
END;
</code></code>

In this
l_out_str := l_out_str || ASCII (l_str_tok) - 55;

If the length of l_out_stris >39 , the concat operator appending value as '00' if l_str_tok is a alphabet irrespective of the value of ASCII (l_str_tok) - 55;
Could you explain me why it is appending zeros.
The maximum length of numeric that oracle allows is 39.
The issue is fixed using below by changing the logic as below.
ELSE
l_ascii := ASCII (l_str_tok) - 55;
l_out_str := l_out_str || l_ascii;
END IF;

Thank you in advance.

and Chris said...

Beware implicit conversions!

If you concatenate a formula with a string, Oracle implicitly converts the whole expression to a number:

select dump('1' || 1-0), dump(11), dump('11') from dual;

DUMP('1'||1-0)      DUMP(11)            DUMP('11')        
------------------- ------------------- -------------------
Typ=2 Len=2: 193,12 Typ=2 Len=2: 193,12 Typ=96 Len=2: 49,49


Note how dump('1' || 1-0) = dump(11), not the dump of string '11'.

The maximum precision of a number in Oracle is 38 digits. This is why you get trailling zeros when you go beyond this:

http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements001.htm#SQLRF30020

Splitting the process in two removes this implicit conversion. You're back to concatenating strings again. You could also achieve this by putting to_char around the formula.

select dump('1' || to_char(1-0)), dump(11), dump('11') from dual;

DUMP('1'||TO_CHAR( DUMP(11)            DUMP('11')        
------------------ ------------------- -------------------
Typ=1 Len=2: 49,49 Typ=2 Len=2: 193,12 Typ=96 Len=2: 49,49

Rating

  (1 rating)

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

Comments

sujatha, October 14, 2015 - 3:50 pm UTC

Thanks Chris.Well clarified.