当在Oracle中将VARCHAR2的大小声明为1字节时,这意味着什么?

28

我知道我可以声明一个varchar2,并指定它应该能够容纳的字符数。

然而,在我正在工作的 Oracle 数据库中,我发现一个字段(名为 PDF)被定义如下:

VARCHAR2(1 BYTE)

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

另一个相关的问题:一个VARCHAR和一个VARCHAR2有什么区别?


1
可能是varchar和varchar2之间的区别是什么?的重复问题。 - Ian Carpenter
1
请仅返回翻译后的文本:可能是https://dev59.com/2XVD5IYBdhLWcg3wHnyd的副本 - Ian Carpenter
请参阅NLS_LENGTH_SEMANTICS参数:https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:29518831139714 - ibre5041
2
在您的情况下,BYTE和CHAR之间的区别是没有意义的。Oracle不支持布尔类型,因此通常将其实现为“CHAR(1)”。具有最大长度为一个字节的可变长度字符串是毫无意义的。 - ibre5041
4个回答

29
您可以将列/变量声明为varchar2(n CHAR)和varchar2(n byte)。
n CHAR表示变量将容纳n个字符。在多字节字符集中,您不总是知道要存储多少字节,但确实想要保证存储一定数量的字符。
n字节只是您想要存储的字节数。
varchar已经被弃用,请不要使用。 varchar和varchar2之间有什么区别?

可能是历史悠久的问题。最初,一个字符是一个字节。然后引入了多字节字符,长度的含义突然变得可以有多种解释。 - Rene
1
我觉得很奇怪,当声明一个数据类型来存储文本字符时,你可以选择指定存储字节数。 底层存储大小需要根据相应的文本编码由数据库引擎透明地处理。 例如,作为用户,如果我需要使用UTF-8编码存储X个文本字符,数据库引擎需要在内部计算出需要多少存储空间。让用户设置这个值会给问题留下后门。 - cvacca
2
有一个数据库参数NLS_LENGTH_SEMANTICS可以处理这个问题。 - Rene

28

VARCHAR 数据类型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 个字符。

请参见此示例( 在 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

另请参阅BYTE和CHAR语义用法的示例和限制(NLS_LENGTH_SEMANTICS)(文档ID 144808.1)


7

回答你的第一个问题:
是的,它意味着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> 

接下来回答你的问题:

  1. VARCHAR 可以存储最多 2000个字符,而 VARCHAR2 可以存储最多 4000个字符
  2. 如果我们将数据类型声明为VARCHAR,则它将占用空值的空间,在VARCHAR2数据类型的情况下,它将不占用任何空间。

4

这意味着每个字符只会分配一个字节 - 所以如果你使用的是多字节字符集,你的1个字符就无法适应

如果你知道你至少需要为1个字符腾出足够的空间,请不要使用BYTE语法,除非你确切地知道需要多少空间来存储该字节

如果不确定,请使用VARCHAR2(1 CHAR)

在此处Difference between BYTE and CHAR in column datatypes有相同的解释

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

在Oracle中,请不要使用VARCHAR


2
此外,在12c中,varchar2的最大长度现在是32k,而不是4000。是的,但需要在SYSTEM级别上显式设置MAX_STRING_SIZEEXTENDED,否则默认值将为4000 - Lalit Kumar B
感谢您的帮助,+Lalit。 - thatjeffsmith
只要字符仅使用一个字节,例如在UTF-8中最高到CHR(127),它也适用于多字节字符集。 - Wernfried Domscheit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接