8

昨日の質問にこの回答をしましたが、手動で更新するのではなく、計算された値にVIRTUAL COLUMNを使用することを提案しました。

私は自分でテストを行い、2 つのNUMBER型の列を連結する際に仮想列式が取るデータ サイズの問題を突き止めました。ただし、2 つの文字を連結している間は問題ありません。

データベースのバージョン:

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 つの文字型の列を連結しても問題はありません。

テスト ケース 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 バイトであるのに、なぜVIRTUAL COLUMNがそれだけのサイズを占めるのか、 81 バイトかかります。

lengthを確認すると、値は正しいのですが、データ サイズがはるかに大きくなっています。たとえば、長さは 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 Alex Poole に感謝します。暗黙的な変換については考えていなかったので、式を明示的に 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>
4

1 に答える 1

9

あなたの数は制限されていません。1 桁の (正の) 数値の場合、連結された長さは 3 つしかないことがわかっていますが、仮想列は任意の数値に対して十分な大きさでなければならないため、暗黙的な形式モデル (38 有効数字、小数点記号と記号; @collspar の語彙化)。

そうは言っても、数値列を制約しても仮想列の長さには反映されません.両方の列を作成してもNUMBER(1,0)、81文字を必要とする連結が残ります. 生成された値の部分文字列を取得しても機能しません。この場合は取得しORA-12899: value too large for column "TEXT" (actual: 10, maximum: 40)ます。to_char()) などの呼び出しごとにフォーマット モデルを指定するFM999と機能しますが、全体の長さを直接制限するのではなく、アンダースコアの両側の値を制限します。

列のサイズを制限したい場合は、同じデータ型とサイズにキャストできます。これはより明示的です。

text VARCHAR2(10) generated always as 
    (cast(to_char(id)||'_'||to_char(num) as VARCHAR2(10))) VIRTUAL
于 2015-02-17T08:17:38.963 に答える