你看到了之间的区别字符和字节长度语义 http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements001.htm#i45694:
您必须指定 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));
如果您的源数据是五个字符,但包含任何多字节字符,则bytes将超过五个:
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
来自dump()
您可以看到之后的值Testing
(54,65,73,74,69,6e,67
) 以及空格和破折号之前 (20,2d
) 你有c2,a0
,即UTF-8 多字节不间断空格字符 http://www.fileformat.info/info/unicode/char/00a0/index.htm。 (您经常会在从 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.
或者,如果可能并且对您的数据有意义,则将任何意外的多字节字符替换为单字节等效字符;在这种情况下是一个正常的空间might工作,但任何替代都会破坏实际上可能很重要的信息。