oracle-databasesubstr

Oracle SUBSTR results in longer column?


It seems that SUBSTR can result in a longer column? What's going on here?

CREATE TABLE t (
    long_field VARCHAR2(1024)
);
SELECT
    column_name,
    data_length
FROM
    all_tab_cols
WHERE
    table_name = 'T';
COLUMN_NAME DATA_LENGTH
LONG_FIELD 1024
INSERT INTO t ( long_field ) VALUES ( 'abcdef' );

CREATE TABLE t2
    AS
        SELECT
            substr(long_field, instr(long_field, 'c') + 1) short_field
        FROM
            t;
SELECT
    column_name,
    data_length
FROM
    all_tab_cols
WHERE
    table_name = 'T2';
COLUMN_NAME DATA_LENGTH
SHORT_FIELD 4096

I'm on Oracle 18:

select BANNER
from V$VERSION;
BANNER
Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production

Solution

  • SUBSTR returns a VARCHAR2(4000) as that is the maximum length sub-string that could be returned from the function.

    Just because your function substr(long_field, instr(long_field, 'c') + 1) returns 'def' doesn't mean that it changes the data-type to have a data-length that is the bounded by the data (i.e. VARCHAR2(3)) as SUBSTR could still (for other data) return a 4000 byte string.

    If you want a lower data length then use CAST:

    CREATE TABLE t3 AS
      SELECT CAST(
               substr(long_field, instr(long_field, 'c') + 1)
               AS VARCHAR2(10)
             ) short_field
      FROM   t;
    

    Then the data dictionary will contain:

    TABLE_NAME COLUMN_NAME DATA_LENGTH
    T3 SHORT_FIELD 10
    T2 SHORT_FIELD 4000

    fiddle