Oracle中VARCHAR2的大小声明为1字节是啥意思?

Posted

技术标签:

【中文标题】Oracle中VARCHAR2的大小声明为1字节是啥意思?【英文标题】:What does it mean when the size of a VARCHAR2 in Oracle is declared as 1 byte?Oracle中VARCHAR2的大小声明为1字节是什么意思? 【发布时间】:2015-09-01 02:57:14 【问题描述】:

我知道我可以声明一个 varchar2 使用它应该能够包含的字符数。

但是,在我正在处理的Oracle 数据库中,我发现一个字段(名为 PDF)的定义如下:

VARCHAR2(1 BYTE)

这是什么意思?它可以包含多少个字符?

另一个相关问题:VARCHARVARCHAR2 有什么区别?

【问题讨论】:

What is the difference between varchar and varchar2? 的可能重复项 和***.com/questions/81448/…的可能副本 另见 NLS_LENGTH_SEMANTICS 参数:asktom.oracle.com/pls/asktom/… 我认为在你的情况下 BYTE 和 CHAR 之间的区别是没有意义的。 Oracle 不支持布尔类型,所以它通常实现为CHAR(1)。具有最大的可变长度字符串。一个字节的长度是无意义的。 【参考方案1】:

VARCHAR datatype 与 VARCHAR2 数据类型同义。为避免可能的行为变化,请始终使用 VARCHAR2 数据类型来存储可变长度字符串。

如果您的数据库在单字节字符集(例如US7ASCIIWE8MSWIN1252WE8ISO8859P1)上运行,则使用VARCHAR2(x BYTE)VARCHAR2(x CHAR) 没有任何区别。

只有当您的数据库在多字节字符集(例如 AL32UTF8AL16UTF16)上运行时才会有所不同。您可以在此示例中简单地看到它:

CREATE TABLE my_table (
    VARCHAR2_byte VARCHAR2(1 BYTE), 
    VARCHAR2_char VARCHAR2(1 CHAR)
);

INSERT INTO my_table (VARCHAR2_char) VALUES ('€');
1 row created.

INSERT INTO my_table (VARCHAR2_char) VALUES ('ü');
1 row created.

INSERT INTO my_table (VARCHAR2_byte) VALUES ('€');
INSERT INTO my_table (VARCHAR2_byte) VALUES ('€')
Error at line 10
ORA-12899: value too large for column "MY_TABLE"."VARCHAR2_BYTE" (actual: 3, maximum: 1)

INSERT INTO my_table (VARCHAR2_byte) VALUES ('ü')
Error at line 11
ORA-12899: value too large for column "MY_TABLE"."VARCHAR2_BYTE" (actual: 2, maximum: 1)

VARCHAR2(1 CHAR) 表示您最多可以存储 1 个字符,无论它有多少字节。如果是 Unicode,一个字符最多可占用 4 个字节。

VARCHAR2(1 BYTE) 表示您可以存储一个最多占用的字符。 1 个字节。

如果您未指定BYTECHAR,则默认值取自NLS_LENGTH_SEMANTICS 会话参数。

除非您有 Oracle 12c,您可以在其中设置 MAX_STRING_SIZE=EXTENDED 限制为 VARCHAR2(4000 CHAR)

但是VARCHAR2(4000 CHAR) 并不意味着您可以保证最多存储 4000 个字符。限制仍然是 4000 字节,所以在最坏的情况下,您最多只能在该字段中存储 1000 个字符。

看这个例子( in UTF-8 占用 3 个字节):

CREATE TABLE my_table2(VARCHAR2_char VARCHAR2(4000 CHAR));

BEGIN
    INSERT INTO my_table2 VALUES ('€€€€€€€€€€');
    FOR i IN 1..7 LOOP
        UPDATE my_table2 SET VARCHAR2_char = VARCHAR2_char ||VARCHAR2_char;
    END LOOP;
END;
/

SELECT LENGTHB(VARCHAR2_char) , LENGTHC(VARCHAR2_char) FROM my_table2;

LENGTHB(VARCHAR2_CHAR) LENGTHC(VARCHAR2_CHAR)
---------------------- ----------------------
                  3840                   1280
1 row selected.


UPDATE my_table2 SET VARCHAR2_char = VARCHAR2_char ||VARCHAR2_char;

UPDATE my_table2 SET VARCHAR2_char = VARCHAR2_char ||VARCHAR2_char
Error at line 1
ORA-01489: result of string concatenation is too long

另见Examples and limits of BYTE and CHAR semantics usage (NLS_LENGTH_SEMANTICS) (Doc ID 144808.1)

【讨论】:

【参考方案2】:

这意味着每个字符只分配一个字节 - 所以如果您使用多字节字符集,您的 1 个字符将不适合

如果您知道必须至少有足够的空间容纳 1 个字符,请不要使用 BYTE 语法,除非您确切知道需要多少空间来存储该字节

如有疑问,请使用 VARCHAR2(1 CHAR)

同样的问题在这里Difference between BYTE and CHAR in column datatypes

另外,在 12c 中,varchar2 的最大值现在是 32k,而不是 4000。如果您需要更多,请使用 CLOB

在 Oracle 中,不要使用 VARCHAR

【讨论】:

另外,在 12c 中,varchar2 的最大值现在是 32k,而不是 4000。 是的,但需要通过将 MAX_STRING_SIZE 设置为在 SYSTEM 级别明确设置EXTENDED,否则默认为4000 感谢 +Lalit 的帮助 它也适用于多字节字符集,只要字符只使用一个字节,例如在 UTF-8 中最高为 CHR(127)【参考方案3】:

回答你的第一个问题: 是的,这意味着 1 个字节分配给 1 个字符。看这个例子

SQL> conn / as sysdba
Connected.
SQL> create table test (id number(10), v_char varchar2(10));

Table created.

SQL> insert into test values(11111111111,'darshan');
insert into test values(11111111111,'darshan')
*
ERROR at line 1:
ORA-01438: value larger than specified precision allows for this column


SQL> insert into test values(11111,'darshandarsh');
insert into test values(11111,'darshandarsh')
*
ERROR at line 1:
ORA-12899: value too large for column "SYS"."TEST"."V_CHAR" (actual: 12,
maximum: 10)


SQL> insert into test values(111,'Darshan');

1 row created.

SQL> 

然后回答您的下一个问题: varchar2varchar的区别:

    VARCHAR 最多可以存储2000 bytes 个字符,而VARCHAR2 最多可以存储4000 bytes 个字符。 如果我们声明数据类型为VARCHAR,那么它将占用NULL values的空间,如果是VARCHAR2数据类型,它将not占用任何空间。

【讨论】:

【参考方案4】:

您可以将列/变量声明为 varchar2(n CHAR) 和 varchar2(n byte)。

n CHAR 表示该变量将包含 n 个字符。在多字节字符集中,您并不总是知道要存储多少字节,但您确实希望保证存储一定数量的字符。

n bytes 仅表示您要存储的字节数。

varchar 已弃用。不要使用它。 What is the difference between varchar and varchar2?

【讨论】:

可能是历史性的。起初,一个字符是一个字节。然后引入了多字节字符,长度的含义突然变得有多种解释。 我觉得很奇怪,在声明存储文本字符的数据类型时,您可以选择指定存储字节数。底层存储大小需要由 db 引擎根据相应的文本编码透明地处理。例如,如果作为用户,我需要使用 UTF-8 编码存储 X 个文本字符,则数据库引擎需要在内部计算出为此需要多少存储空间。让用户设置为麻烦打开了大门。 有一个数据库参数 NLS_LENGTH_SEMANTICS 可以解决这个问题。

以上是关于Oracle中VARCHAR2的大小声明为1字节是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

oracle中字段类型varchar2最大长度是多少?

新手小白,在oracle中varchar2类型,能设置最大值吗

Oracle 19c对VARCHAR2的限制

Oracle 19c对VARCHAR2的限制

mysql与oracle 长度区别

oracle 中比较日期大小,日期定义的是varchar2类型的,比如'2011-10-21'