oracle - 修复 Oracle 4000 字符中允许的最大长度

标签 oracle plsql oracle11g triggers database-trigger

我目前正在使用 Oracle 11g。根据我的要求,我需要将前 4000 个(最大限制)字符存储到我的变量(在触发器中使用)。

为此,我正在使用 VarName = SUBSTR 函数(VarName, 1, 4000),但它似乎没有存储任何内容(我正在传递 '111...'(要存储的 4096 个字符),我想从中存储 (' 111...') 仅限前 4000 个字符)。

它适用于 4 个字符,但不适用于最大限制。我尝试将长度设为 3999、3000,但没有任何效果。

请仔细研究一下,并为此建议我一些解决方案。

(*注意:我无法将变量类型从 varchar 更改为 clob,因为此列已经拥有数百万个遗留数据。)

*修改:我尝试使用 Substr 长度 2048 ,是工作 但一旦我是 为 substr 提供 2049 个字符,它再次变为空 .
但在 数据类型字段值定义为 VARCHAR2(4000 CHAR) .

最佳答案

如果我是对的,你最好升级到oracle 12。让我解释一下:

Oracle(包括版本 11)对 char/varchar 列的硬限制为 4000 BYTES,并且无法通过简单地将列声明为“varchar2(4000 CHAR)”来克服此限制 .

如果您的数据库使用多字节字符集,则该限制仍然存在,因此只有满足以下两个条件,您才能实际存储 4000 个字符:

  • 在您的字符集中,有些字符仅占用一个字节
  • 您要存储的字符串仅使用编码为单个字节的字符组成

    例如:如果你的数据库字符集是UTF8,“A”字符占一个字节,而“à”字符需要两个字节:
                |  Bytes required       |Bytes required       |   Bytes required  
      string    |  if database charset  |if database charset  |  if database charset       
                |  is  ASCII            |is  UTF8             |   is  UTF16
      --------- |-------------------------------------------------------------------
       "A"      |  1 byte               |   1 bytes           |   2 bytes 
       "à"      |  1 byte               |   2 bytes           |   2 bytes 
       "àA"     |  2 byte               |   3 bytes           |   4 bytes       
    

  • 所以在 VARCHAR2(4000 CHAR) 列中,在 UTF8 数据库中,您将能够存储由 4000 个“A”字符组成的字符串,但如果您使用 4000 个“à”字符,它将被限制为 2000 个字符:在 UTF8 中任何其代码 unicode number >= 128(即:它不是 ASCII 字符)的字符都需要多个字节。在 UTF16 中,任何字符至少占用 2 个字节。

    通过查看您所描述的症状(以及您的名字),我认为您没有使用单字节字符集……而且我还认为您使用的大多数字符至少需要两个字节,所以这里是2000 个字符实际限制的原因:您面临 4000 个字节的硬限制。

    我认为对你来说唯一“简单”的解决方案是将数据库升级到 oracle 12,在那里这个硬限制可以提高到 32000 字节(AFAIK 它不会“开箱即用”:你需要设置它相应地,在数据库创建期间)。

    如果您使用提高的限制创建 oracle 12 数据库,您的 varchar2(4000 CHAR) 列将不再满足硬限制。

    还要记住,当您通常将列声明为 VARCHAR2(4000) 时,oracle 默认将其解释为 VARCHAR2(4000 BYTE)。这个默认值可以通过在你的 session 中执行来改变:
     alter session set NLS_LENGTH_SEMANTICS='CHAR'
    

    TEORICALLY 可以在整个数据库和所有 session 的实例级别设置它,但是 oracle 警告您不要这样做,因为系统会行为不端,因此请坚持在 session 级别使用它。

    希望这可以帮助。

    附言也许你会发现这个提示也很有用:

    在我的数据库中,我编写了一个“登录后”触发器,该触发器自动执行该更改 session 仅适用于我的应用程序的用户
    CREATE OR REPLACE TRIGGER TRG_MYAPP_AFTER_LOGON
    AFTER LOGON on database
    declare
        function IsMyAppUser return boolean is
        cnt number;
        begin
           -- if the user is the owner of the schema, all its commands are expected
           -- to use the "char" length semantics 
           if user = 'MYAPP' then
              return true;
           end if;
           --- this is specific to my app: I have a table that lists the login names
           --- of the users who have been created only with the purpose of using the app
           select count(*) into cnt  
           from my_app_users u 
           where u.usr_login=user 
             and ROWNUM=1;
           return cnt>0;
        end;
    BEGIN
       if IsMyAppUser then
           execute immediate 'alter session set nls_length_semantics = ''CHAR''';
       end if;
    END TRG_QBF_AFTER_LOGON;
    

    关于oracle - 修复 Oracle 4000 字符中允许的最大长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52040355/

    相关文章:

    sql - 无需索引即可提高 oracle 查询性能

    sql - PL/SQL : IF-ELSIF-ELSE -> ELSE block is not considered as a basic block

    java.sql.SQLException : OALL8 is in an inconsistent state on JBoss 6. 1 EAP

    sql - 必须相互更新的两个表的触发器替代方案

    sql - SQL在Oracle中搜索对象(包括存储过程)

    sql - 查询的开始和结束时间

    java - Commons DBUtils Oracle 11.2.0.4 与 Java 1.7 绑定(bind)参数 SQLException ORA-00942

    oracle11g - 连接到 10g 和 11g 数据库的 Oracle 11g 客户端

    oracle - 如何在oracle 11g中找到不可见的表?

    oracle - "table view does not exist"使用外部表时出错