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 |
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 |