ORA-12899 值对于列来说太大,尽管长度相同

新手上路,请多包涵

我正在运行以下查询。但是得到 ORA-12899。尽管我试图插入的字符串长度是 30。

 INSERT INTO TABLE1 SELECT * FROM temp_Table1 where LENGTH(column1)=30;

SQL Error: ORA-12899:value too large for column "TABLE1"."column1" (actual: 31, maximum: 30)

select column1 from temp_Table1 where LENGTH(column1)=30;

Testing  - HLC/TC Design Corre

Desc temp_Table1

column1 VARCHAR2(30)

Desc Table1

column1 VARCHAR2(30)

原文由 Shitu 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

您会看到 字符和字节长度语义 之间的区别:

您必须为 VARCHAR2 列指定最大长度。此最大值必须至少为 1 个字节,尽管实际存储的字符串允许为零长度字符串 (“)。您可以使用 CHAR 限定符,例如 VARCHAR2(10 CHAR),以字符而不是字节给出最大长度。字符在技术上是数据库字符集的代码点。您可以使用 BYTE 限定符,例如 VARCHAR2(10 BYTE),明确给出以字节为单位的最大长度。如果在创建具有此列或属性的数据库对象时,列或属性定义中未包含显式限定符,则长度语义由创建对象的会话的 NLS_LENGTH_SEMANTICS 参数的值确定。

如果您的会话使用字节语义,则表中的列将默认为:

 select value from nls_session_parameters where parameter = 'NLS_LENGTH_SEMANTICS';

VALUE
----------------------------------------
BYTE

create table t42(text varchar2(5));

Table T42 created.

select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';

C
-
B

这与明确执行以下操作相同:

 create table t42(text varchar2(5 byte));

如果您的源数据是五个字符但包含任何多字节字符,则 字节 数将超过五个:

 insert into t42 (text) values ('Hello');

1 row inserted.

insert into t42 (text) values ('Señor');

SQL Error: ORA-12899: value too large for column "SCHEMA"."T42"."TEXT" (actual: 6, maximum: 5)

这就是你所看到的。当您从其他表中插入值时,您将过滤值的长度,但 length() 计算字符而不是字节。有一个 lengthb() 函数可以计算字节数。如果您检查您选择的 30 个字符值的字节长度,您会发现它实际上是 31 个字节,因此其中一个字符是多字节的。

 with t42 (text) as (
  select 'Hello' from dual
  union all select 'Señor' from dual
  union all select 'Testing  - HLC/TC Design Corre' from dual
)
select text, length(text) as chars, lengthb(text) as bytes, dump(text, 16) as hex
from t42;

TEXT                            CHARS BYTES HEX
------------------------------- ----- ----- ----------------------------------------------------------------------------------------------------------
Hello                               5     5 Typ=1 Len=5: 48,65,6c,6c,6f
Señor                               5     6 Typ=1 Len=6: 53,65,c3,b1,6f,72
Testing  - HLC/TC Design Corre     30    31 Typ=1 Len=31: 54,65,73,74,69,6e,67,c2,a0,20,2d,20,48,4c,43,2f,54,43,20,44,65,73,69,67,6e,20,43,6f,72,72,65

From the dump() values you can see that after Testing ( 54,65,73,74,69,6e,67 ) and before the space and dash ( 20,2d ) you have c2,a0UTF-8 多字节不间断空格字符。 (您经常在从 Word 文档复制的文本中看到,以及大引号和其他非 ASCII 范围字符)。

您可以更改插入以过滤 LENGTHB(column1)=30 (这将排除您当前找到的行),或者将列定义更改为 30 个字符而不是 30 个字节:

 drop table t42;

Table T42 dropped.

create table t42(text varchar2(5 char));

Table T42 created.

select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';

C
-
C

insert into t42 (text) values ('Hello');

1 row inserted.

insert into t42 (text) values ('Señor');

1 row inserted.

或者,如果可能并且对您的数据有意义,则将任何意外的多字节字符替换为单字节等效字符;在这种情况下,一个正常的空间 可能会 起作用,但任何替换都会破坏可能实际上很重要的信息。

原文由 Alex Poole 发布,翻译遵循 CC BY-SA 3.0 许可协议

由于目标表数据库中的 NLS 设置不同,它可能需要目标中的更多字节。尝试将表更改为 alter Table1 modify column1 varchar2(30 char)

原文由 lakshmi tatavarty 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进