VARCHAR2 field boundary size in Oracle

Asked

Viewed 15,292 times

8

I got a column with the guy VARCHAR2 (4000 CHAR) and I’m testing the field boundary size VARCHAR2 in the Oracle. I thought there was a limit to 4000 bytes in the field, even if specifying the value 4000 in characters, due to this error already happened at work and the problem has been solved.

When trying to insert a string containing more than 2000 characters á, an error occurred saying that the value was too great for the field. This was because the character á occupied 2 bytes in the database. However, today the same test was done and this time the database entered the value correctly.

This occurred on only one of the machines where I work, which has the same configuration as the others.

What might be going on?

Is there any configuration in Oracle that may be allowing to insert a string with more than 4000 bytes?

  • 1

    You’re probably wearing a encoding different. http://answall.com/q/21230/101 Or if it’s a encoding that each character occupies a different size may be the different text that made it fit.

  • How it is inserted into the database, through an application such as PL/SQL or SQL?

  • I tried to insert by SQL Developer and also through the application I am developing. The machine in which the problem occurred has Windows. The rest are variants of Linux or Mac. What we’re finding is that the problem is Windows encoding, but we’re not sure yet.

  • Depending on the client you are using you can specify the encoding. This encoding setting can be done in client software or even in the connection string of your app. Do you need to work with VARCHAR2? I ask this because depending on the amount of characters it would be interesting to change to a different type of data.

3 answers

3


VARCHAR2 stores alphanumeric characters of variable size, between 1 and 4000 bytes or characters. The default size of this column is set in bytes, in your case, this may be the problem.

When creating a VARCHAR2 column we can specify whether the data will be counted as bytes or characters. There is a big difference between these two options, for example, if you use the UTF-8 Encode, 1 single character can be stored in up to 3 bytes, so the storage limit can drop considerably if there are too many accented words/letters, in these cases in this case it would be better to specify the storage of the column in Character.

More information on: https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm

1

The answer accepted for the question is correct and the documentation has a lot of information, but I will give a practical example because I have suffered enough with this oracle.

Let’s start by checking, with the SQL below, the value of NLS_CHARACTERSET, which is the "cause" of the problem:

SELECT *
FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';

If you are using UTF8, as already reported, a single character can occupy 3 bytes. Then, in a database configured this way, if you run the following SQL:

CREATE TABLE NLS_TESTS (
    COMCHAR VARCHAR2(3 CHAR),
    SEMCHAR VARCHAR2(3)
);

INSERT INTO NLS_TESTS VALUES('aei', 'aei'); --Será inserido
INSERT INTO NLS_TESTS VALUES('áéí', 'áéí'); --Não será inserido!!
INSERT INTO NLS_TESTS VALUES('áéí', 'aei'); --Será inserido!!

The second insert will not be inserted as the SEMCHAR VARCHAR2(3) uses the NLS_LENGTH_SEMANTICS current to determine the size of the text. That is, to UTF8 if the character occupies 2 bytes, then these 2 bytes will actually be occupied in the column.

Already the third insert will be executed without error as the column COMCHAR VARCHAR2(3 CHAR) is using 'CHAR', which basically indicates that the column should have enough space for 3 characters, regardless of how many bytes this takes.

I’ve been through this problem where changing column to column for VARCHAR2(x CHAR) was not feasible, one way around this would be by using the following code in your current transaction, to change the NLS_CHARACTERSET session:

declare
    v_s_CharacterSet VARCHAR2(160);
begin
    select VALUE
    into v_s_CharacterSet
    from NLS_DATABASE_PARAMETERS
    where PARAMETER = 'NLS_CHARACTERSET';
    if v_s_CharacterSet in ('UTF8', 'AL32UTF8') then
        execute immediate 'alter session set nls_length_semantics=char';
    end if;
end;

This also explains why when running from another computer it worked. The session that was opened where it worked, did not use UTF8 or AL32UTF8.

-3

Browser other questions tagged

You are not signed in. Login or sign up in order to post.