Oracle varchar2或char类型的byte和char的区别

简介:

Oracle定义字符串类型VARCHAR2和CHAR指定长度的用法如下:

varchar2(<SIZE> <BYTE|CHAR>) <SIZE>是介于1~4000之间的一个数,表示最多占用4000字节的存储空间。

char(<SIZE> <BYTE|CHAR>) <SIZE>是介于1~2000之间的一个数,表示最多占用2000字节的存储空间。

那其中的BYTE和CHAR有什么区别呢

  • BYTE,用字节指定:VARCHAR2(10 BYTE)。这能支持最多10字节的数据,在一个多字节字符集中,这可能只是两个字符。采用多字节字符集时,字节与字符并不相同。

  • CHAR,用字符指定:VARCHAR2(10 CHAR)。这将支持最多10字符数据,可能是多达40字节的信息。另外,VARCHAR2(4000 CHAR)理论上支持最多4000个字符的数据,不过由于Oracle中字符串数据类型限制为4000字节,所以可能无法得到全部4000个字符。

使用UTF8之类的多字节字符集时,建议你在VARCHAR2/CHAR定义中使用CHAR修饰会,也就是说,使用VARCHAR2(30 CHAR),而不是VARCHAR2(30),因为你的本意很可能是定义一个实际上能存储30字符数据的列。还可以使用会话参数或系统参数NLS_LENGTH_SEMANTICS来修改默认行为,即把默认设置BYTE改为CHAR。不建议在系统级修改这个设置,而应该使用ALTER SESSION修改会话级。还有重要的一点,VARCHAR2中存储的字节数上界是4000。不过,即使你指定了VARCHAR(4000 CHAR),可能并不能在这个字段中放下4000个字符实际上,采用你选择的字符集时,如果所有字符都要用4个字节来表示,那么这个字段中就只能放下1000个字符!

下面使用一个小例子展示BYTE和CHAR之间的区别,并显示出上界的作用。

测试环境11.2.0.4,是在多字节字符集数据库上完成的,在此使用了字符集AL32UTF8,这个字符集支持最新版本的Unicode标准,采用一种变长方式对每个字符使用1~4个字节进行编码

1
2
3
4
5
6
7
8
9
10
11
12
zx@ORCL>col value  for  a30
zx@ORCL>col parameter  for  a30
zx@ORCL> select  from  nls_database_parameters  where  parameter= 'NLS_CHARACTERSET' ;
 
PARAMETER              VALUE
------------------------------ ------------------------------
NLS_CHARACTERSET           AL32UTF8
zx@ORCL>show parameter nls_leng
 
NAME                      TYPE                 VALUE
------------------------------------ --------------------------------- ------------------------------
nls_length_semantics             string                   BYTE

创建测试表

1
2
3
zx@ORCL> create  table  t (a varchar2(1),b varchar2(1  char ),c varchar2(4000  char ));
 
Table  created.

现在,这个表中插入一个UTF字符unistr('\00d6'),这个字符长度为2个字节,可以观察到以下结果:

1
2
3
4
5
6
7
8
9
10
11
zx@ORCL> select  length(unistr( '\00d6' )),lengthb(unistr( '\00d6' ))  from  dual;
 
LENGTH(UNISTR( '\00D6' )) LENGTHB(UNISTR( '\00D6' ))
----------------------- ------------------------
               1             2
 
zx@ORCL> insert  into  t (a)  values  (unistr( '\00d6' ));
insert  into  t (a)  values  (unistr( '\00d6' ))
                           *
ERROR  at  line 1:
ORA-12899: value too large  for  column  "ZX" . "T" . "A"  (actual: 2, maximum: 1)

这说明:VARCHAR(1)的单位是字节而不是字符。这里确实只有一个Unicode字符,但是它在一个字节中放不下;将应用从单字节定宽字符集移植到一个多字节字符集时,可能会发现原来在字段中能放下的文本现在却无法放下。第二点的原因是:在一个单字节字符集中,包含20个字符的字符串长度就是20字节,完全可以在VARCHAR2(20)中放下。不过在一个多字节字符集中,20个字符的长度可以达到80字节(如果每个字符用4个字节表示),这样一杰,20个Unicode字符很可能无法在20个字节中放下。你可能会考虑将DDL修改为VARCHAR2(20 CHAR),或在运行DDL创建表时使用前面提到的NLS_LENGTH_SEMENTICS会话参数。

插入包含一个字符的字段时观察到以下结果:

1
2
3
4
5
6
7
8
9
10
zx@ORCL> insert  into  t (b)  values  (unistr( '\00d6' ));
 
1 row created.
 
zx@ORCL>col dump  for  a30
zx@ORCL> select  length(b),lengthb(b),dump(b) dump  from  t;
 
  LENGTH(B) LENGTHB(B) DUMP
---------- ---------- ------------------------------
      1     2 Typ=1 Len=2: 195,150

这个INSERT成功了,而且可以看到,所有插入数据的长度(LENGTH)就是一个字符,所有字符串函数都以字符为单位工作。LENGTHB函数(字节长度)显示出这个字段占用了2字节的存储空间,另外DUMP函数显示了这些字节到底是什么。这个例子展示了VARCHAR2(N)并不一定存储N个字符,而只是存储N个字节。

下面测试VARCHAR2(4000)可能存储不了4000个字符

1
2
3
4
5
6
7
8
9
10
11
12
13
zx@ORCL> declare
   2  l_date varchar2(4000  char );
   3  l_ch   varchar2(1  char ) := unistr( '\00d6' );
   4   begin
   5  l_date:=rpad(l_ch,4000,l_ch);
   6   insert  into  t(c)  values (l_date);
   7   end ;
   8  /
declare
*
ERROR  at  line 1:
ORA-01461: can bind a LONG value  only  for  insert  into  a LONG  column
ORA-06512:  at  line 6

在此显示出,一个4000字符的实际上长度为8000字节,这样一个字符串无法永久地存储在一个VARCHAR(4000 char)字段中,这个字符串能放在PL/SQL变量中,因为在PL/SQL中VARCHAR2最大可以达到32K。不过,存储在表中,VARCHAR2则被硬性限制为最多只能存放4000字节。我们可以成功地存储其中2000个字符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
zx@ORCL> declare
   2  l_date varchar2(4000  char );
   3  l_ch   varchar2(1  char ) := unistr( '\00d6' );
   4   begin
   5  l_date:=rpad(l_ch,2000,l_ch);
   6   insert  into  t(c)  values (l_date);
   7   end ;
   8  /
 
PL/SQL  procedure  successfully completed.
 
zx@ORCL>
zx@ORCL> select  length(c),lengthb(c)  from  where  is  not  null ;
 
  LENGTH(C) LENGTHB(C)
---------- ----------
       2000       4000

输出可见,c占用了4000个字节的存储空间。


参考:《9I10G11G编程艺术  深入数据库体系结构》《Oracle Database Globalization Support Guide》






     本文转自hbxztc 51CTO博客,原文链接:http://blog.51cto.com/hbxztc/1893768,如需转载请自行联系原作者







相关文章
|
6月前
|
存储 SQL 关系型数据库
【YashanDB知识库】MySQL迁移至崖山char类型数据自动补空格问题
**简介**:在MySQL迁移到崖山环境时,若字段类型为char(2),而应用存储的数据仅为&#39;0&#39;或&#39;1&#39;,查询时崖山会自动补空格。原因是mysql的sql_mode可能启用了PAD_CHAR_TO_FULL_LENGTH模式,导致保留CHAR类型尾随空格。解决方法是与应用确认数据需求,可将崖山环境中的char类型改为varchar类型以规避补空格问题,适用于所有版本。
|
7月前
|
SQL Oracle 关系型数据库
MySQL 和 Oracle 的区别?
本文对比了Oracle和MySQL数据库的多个方面。Oracle适用于大型数据库,支持高并发和大访问量,市场占有率为40%,安装占用空间较大,约3G;而MySQL适合中小型应用,是开源免费的,安装仅需152M。两者在主键生成、字符串处理、SQL语句、事务处理等方面存在差异。Oracle功能更为强大,尤其在企业级应用中表现突出,而MySQL则以简单易用见长。
843 7
MySQL 和 Oracle 的区别?
|
6月前
|
Oracle 关系型数据库 MySQL
【YashanDB知识库】oracle dblink varchar类型查询报错记录
这篇文章主要介绍了 Oracle DBLINK 查询崖山 DB 报错的相关内容,包括 ODBC 安装配置、数据源配置、dblink 环境配置、问题原因分析及规避方法。问题原因是 dblink 连接其他数据库时 varchar 类型转换导致的,还介绍了 long 类型限制、char 等类型区别,规避方法是修改参数 MAX_STRING_SIZE 支持 32K。
|
8月前
|
Oracle 关系型数据库 数据库
【YashanDB知识库】oracle dblink varchar类型查询报错记录
在使用Oracle DBLink查询VARCHAR类型数据时,可能会遇到多种报错。通过了解常见错误原因,采取合适的解决方法,可以有效避免和处理这些错误。希望本文提供的分析和示例能帮助你在实际工作中更好地处理DBLink查询问题。
215 10
|
7月前
|
存储 SQL 关系型数据库
【YashanDB 知识库】MySQL 迁移至崖山 char 类型数据自动补空格问题
问题分类】功能使用 【关键字】char,char(1) 【问题描述】MySQL 迁移至崖山环境,字段类型源端和目标端都为 char(2),但应用存储的数据为'0'、'1',此时崖山查询该表字段时会自动补充空格 【问题原因分析】mysql 有 sql_mode 控制,检查是否启用了 PAD_CHAR_TO_FULL_LENGTH SQL 模式。如果启用了这个模式,MySQL 才会保留 CHAR 类型字段的尾随空格,默认没有启动。 #查看sql_mode mysql> SHOW VARIABLES LIKE 'sql_mode'; 【解决/规避方法】与应用确认存储的数据,正确定义数据
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
1928 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
12月前
|
存储 Java Windows
java基础(9)数据类型中的char类型以及涉及到的转义字符
Java中的char类型可以存储一个中文字符,因为它占用两个字节。转义字符允许在代码中使用特殊字符,例如`\n`表示换行,`\t`表示制表符,`\\`表示反斜杠,`\'`表示单引号,`\"`表示双引号。可以使用`\u`后跟Unicode编码来表示特定的字符。
333 2
java基础(9)数据类型中的char类型以及涉及到的转义字符
|
11月前
|
SQL 存储 关系型数据库
SQL判断CHAR类型字段不为空的方法与技巧
在SQL查询中,判断一个CHAR类型字段是否不为空是一个常见的需求
|
存储 自然语言处理 编译器
C语言中的char类型
C语言中的char类型
1590 1
|
存储 Oracle 关系型数据库
关系型数据库Oracle备份类型与频率
【7月更文挑战第21天】
208 6