【问题标题】:Oracle varchar2 and unicode textsOracle varchar2 和 unicode 文本
【发布时间】:2021-03-21 15:43:26
【问题描述】:

According to spec VARCHAR2(max_size CHAR) 应该存储 max_size 字符。我观察到 Unicode 文本的其他/奇怪行为。

让我们考虑这个例子:

create table test (id varchar2(3 char) not null, primary key (id));

insert into test(id) values('abc');
insert into test(id) values('ффф');

Query 1 ERROR: ORA-12899: value too large for column "TEST"."TEST"."ID" (actual: 6, maximum: 3)

所以 varchar2 3 chars 实际上和 byte 的意思是一样的? 否 :)

create table test (id varchar2(3 byte) not null, primary key (id))

insert into test(id) values('abc')
insert into test(id) values('ффф')

Query 1 ERROR: ORA-12899: value too large for column "TEST"."TEST"."ID" (actual: 18, maximum: 3)

我的问题仍然是如何告诉 Oracle varchar2 长度适用于 Unicode 文本(更准确地说是 UTF8)?

更新:是否可以写下一个 SQL 查询来显示所有长度为字节的表/列?

实际上,我的问题分为两部分,TablePlus 的查询编码不正确,随机列的字节长度(无字符后缀):)

更新 2:感谢@Wernfried Domscheit!

查询显示带有varchar2 的表和列,该长度在bytes 中提供:

SELECT TABLE_NAME, COLUMN_NAME, DATA_LENGTH, CHAR_USED
FROM USER_TAB_COLUMNS WHERE DATA_TYPE = 'VARCHAR2' AND CHAR_USED = 'B'

【问题讨论】:

    标签: sql oracle unicode varchar varchar2


    【解决方案1】:

    你的例子对我有用:

    SELECT * 
    FROM V$NLS_PARAMETERS 
    WHERE PARAMETER = 'NLS_CHARACTERSET';
    
    PARAMETER          VALUE      
    ------------------------------
    NLS_CHARACTERSET   AL32UTF8   
    
    1 row selected.
    
    
    
    CREATE TABLE TEST (ID VARCHAR2(3 CHAR));
    Table created.
    
    INSERT INTO TEST(ID) VALUES('abc');
    1 row created.
    
    INSERT INTO TEST(ID) VALUES('ффф');
    1 row created.
    

    可能是你的错字?

    更新:

    您的客户似乎使用了错误的字符设置。

    ф (U+0444: Cyrillic Small Letter Ef) 有这些字节值:

    +-------------------------------------------------------------------------------+
    |Encoding|hex        |dec (bytes)|dec       |binary                             |
    +-------------------------------------------------------------------------------+
    |UTF-8   |D1 84      |209 132    |53636     |11010001 10000100                  |
    |UTF-16BE|04 44      |4 68       |1092      |00000100 01000100                  |
    |UTF-16LE|44 04      |68 4       |17412     |01000100 00000100                  |
    |UTF-32BE|00 00 04 44|0 0 4 68   |1092      |00000000 00000000 00000100 01000100|
    |UTF-32LE|44 04 00 00|68 4 0 0   |1141112832|01000100 00000100 00000000 00000000|
    +-------------------------------------------------------------------------------+
    

    DUMP 应该返回 Typ=1 Len=6 CharacterSet=AL32UTF8: d1,84,d1,84,d1,84 但你会得到 ef,bf,bdU+FFFD: Replacement Character

    你不插入ффф,它被转换成���

    我猜实际上您的客户端使用 UTF-8,但您没有告诉数据库,因此数据库很可能假定客户端使用默认的 US7ASCII(或其他内容)。客户端发送 6 个字节 (d1,84,d1,84,d1,84),但 Oracle 数据库将其解释为 6 个单字节字符。

    通常您使用NLS_LANG 环境变量来定义它。但是,dbeaver 是基于 Java 的,Java/JDBC 不使用 NLS_LANG 设置 - 至少默认情况下不使用。

    【讨论】:

    • 不。 SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET' NLS_CHARACTERSET AL32UTF8 这种行为可以绑定到 Oracle 版本吗?
    • 用你的 SQL 重新检查(复制粘贴到控制台 + 删除现有的测试表)。同样的错误。我的数据库版本是“Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production”
    • 您使用哪种工具?尝试INSERT INTO TEST(ID) VALUES('ф') 并检查DUMP() 实际插入的内容。
    • TablePlus、dbeaver 或 Oracle jdbc(瘦)Java 驱动程序
    • 是的,试试SELECT TABLE_NAME, COLUMN_NAME, DATA_LENGTH, CHAR_USED FROM USER_TAB_COLUMNS WHERE DATA_TYPE = 'VARCHAR2' AND CHAR_USED = 'B' 此外,当您没有指定BYTECHAR 时,默认由会话参数NLS_LENGTH_SEMANTICS 给出
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多