修复了Oracle 4000字符中char允许的最大长度

时间:2018-08-27 13:19:41

标签: 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 ,它是有效的,但是一旦我提供2049个字符进行替换,它又再次变为空。 但是在数据类型中,字段值定义为VARCHAR2(4000 CHAR)

2 个答案:

答案 0 :(得分:2)

如果我是对的,则最好升级到oracle12。让我解释一下:

Oracle(包括最高11版)对char / varchar列的HARD限制为4000 BYTES ,并且不能通过简单地将列声明为“ varchar2( 4000 CHAR)”

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

  1. 您的字符集中的字符仅占用一个字节
  2. 您要存储的字符串仅由编码为单个字节的字符组成

    例如:如果您的数据库字符集为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       
    

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

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

我认为对您来说,唯一的“简单”解决方案是将数据库升级到oracle 12,在此该硬限制可以提高到32000字节(AFAIK并非“开箱即用”:您需要在数据库创建过程中进行相应设置)。

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

还请记住,当您通常将列声明为VARCHAR2(4000)时,oracle默认情况下会将其解释为VARCHAR2(4000 BYTE)。可以通过在会话中执行以下操作来更改此默认值:

 alter session set NLS_LENGTH_SEMANTICS='CHAR'
可以在整个数据库和所有会话的实例级别上设置

TEORICALLY,但 oracle警告您不要这样做,因为系统将无法正常运行,因此请坚持在会话级别上使用它。

希望这会有所帮助。


P.S。也许您会发现以下提示也很有用:

在数据库中,我编写了一个“登录后”触发器,该触发器自动执行,仅更改应用程序用户的会话

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;

答案 1 :(得分:0)

RPADLPAD

我可以这样获得4000个字符的单元格:

select rpad('x',3999, '-'),  v.* 
  from v$version v 
 where rownum=1

给予

|x------[3999 times] | Oracle Database 11g Release 11.2.0.4.0 - 64bit dev|