Объединение чисел в выражении виртуального столбца приводит к ORA-12899: слишком большое значение для столбца

Пока я давал этоответ на вопрос вчера, я предложил использоватьВИРТУАЛЬНАЯ КОЛОННА для вычисленных значений вместо обновления вручную.

Я сделал тест самостоятельно и выяснил проблему с размером данных, который занимает выражение виртуального столбца во времяконкатенации дваЧИСЛО введите столбцы. Тем не менее, нет проблем при объединении двух символов.

Версия БД:

SQL> select banner from v$version where rownum = 1;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production

SQL>

Тестовый пример 1: объединение строк

SQL> CREATE TABLE t(
  2  ID varchar2(2),
  3  num varchar2(2),
  4  text VARCHAR2(10) generated always as (id||'_'||num) VIRTUAL
  5  );

Table created.

SQL>
SQL> INSERT INTO t(ID, num) VALUES ('a', 'e');

1 row created.

SQL> INSERT INTO t(ID, num) VALUES ('b', 'f');

1 row created.

SQL> INSERT INTO t(ID, num) VALUES ('c', 'g');

1 row created.

SQL>
SQL> SELECT * FROM T;

ID NU TEXT
-- -- ----------
a  e  a_e
b  f  b_f
c  g  c_g

SQL>

Таким образом, нет проблем с объединением двух столбцов символьного типа.

Контрольный пример 2: объединяющие числа

SQL> CREATE TABLE t(
  2  ID NUMBER,
  3  num NUMBER,
  4  text VARCHAR2(10) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
  5  );
text VARCHAR2(10) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
*
ERROR at line 4:
ORA-12899: value too large for column "TEXT" (actual: 10, maximum: 81)

Не положено? Ха! Давайте увеличим размер -

SQL> CREATE TABLE t(
  2  ID NUMBER,
  3  num NUMBER,
  4  text VARCHAR2(81) generated always as (to_char(id)||'_'||to_char(num)) VIRTUAL
  5  );

Table created.

SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (2, 5);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (3, 6);

1 row created.

SQL>
SQL> SELECT * FROM T;

        ID        NUM
---------- ----------
TEXT
--------------------------------------------------------------------------------
         1          4
1_4

         2          5
2_5

         3          6
3_6


SQL> set linesize 200
SQL> SELECT * FROM T;

        ID        NUM TEXT
---------- ---------- ----------------------------------------------------------------------------------------------------
         1          4 1_4
         2          5 2_5
         3          6 3_6

SQL>

Итак, что случилось сейчас? Стол создан, но почемуВИРТУАЛЬНАЯ КОЛОННА занимает столько места, когдаожидаемый размер данных всего 3 байтаОднако требуется81 байт.

Проверкадлина, значение верное, однако размер данных намного больше. Например, я ожидаю, что длина будет 3, поэтому я объявляю размер столбца в 10 байт. Но выражение виртуального столбца дает значение, размер которого намного больше этого.

SQL> CREATE TABLE t(
  2  ID NUMBER,
  3  num NUMBER,
  4  text VARCHAR2(10) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
  5  );
text VARCHAR2(10) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
*
ERROR at line 4:
ORA-12899: value too large for column "TEXT" (actual: 10, maximum: 40)


SQL>
SQL> CREATE TABLE t(
  2  ID NUMBER,
  3  num NUMBER,
  4  text VARCHAR2(81) generated always as (length(to_char(id)||'_'||to_char(num))) VIRTUAL
  5  );

Table created.

SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (2, 5);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (3, 6);

1 row created.

SQL>
SQL> SELECT * FROM T;

        ID        NUM TEXT
---------- ---------- ----------------------------------------------------------------------------------------------------
         1          4 3
         2          5 3
         3          6 3

SQL> clear columns
columns cleared
SQL> SELECT * FROM T;

        ID        NUM TEXT
---------- ---------- ---------------------------------------------------------------------------------
         1          4 3
         2          5 3
         3          6 3

Любое понимание более чем приветствуется.

UDPATE Спасибо Алекс Пул. Я не думал о неявном преобразовании, поэтому я не хотел явно выражать CAST. Итак, ниже работает -

SQL> DROP TABLE t PURGE;

Table dropped.

SQL>
SQL> CREATE TABLE t(
  2  ID NUMBER,
  3  num NUMBER,
  4  text VARCHAR2(10) generated always as (cast(to_char(id)||'_'||to_char(num) as varchar2(3))) VIRTUAL
  5  );

Table created.

SQL>
SQL> INSERT INTO t(ID, num) VALUES (1, 4);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (2, 5);

1 row created.

SQL> INSERT INTO t(ID, num) VALUES (3, 6);

1 row created.

SQL>
SQL> SELECT * FROM T;

        ID        NUM TEXT
---------- ---------- ----------
         1          4 1_4
         2          5 2_5
         3          6 3_6

SQL>

Ответы на вопрос(1)

Ваш ответ на вопрос