What does it mean when the size of a VARCHAR2 in Oracle is declared as 1 byte? - sql

I know that I can declare a varchar2 using the number of the characters that it should be able to contain.
However, in an Oracle database on which I am working, I found that a field (named PDF) is defined as follows:
VARCHAR2(1 BYTE)
What does this mean? How many characters can it contain?
Another, related question: What is the difference between a VARCHAR and a VARCHAR2?

You can declare columns/variables as varchar2(n CHAR) and varchar2(n byte).
n CHAR means the variable will hold n characters. In multi byte character sets you don't always know how many bytes you want to store, but you do want to garantee the storage of a certain amount of characters.
n bytes means simply the number of bytes you want to store.
varchar is deprecated. Do not use it.
What is the difference between varchar and varchar2?

The VARCHAR datatype is synonymous with the VARCHAR2 datatype. To avoid possible changes in behavior, always use the VARCHAR2 datatype to store variable-length character strings.
If your database runs on a single-byte character set (e.g. US7ASCII, WE8MSWIN1252 or WE8ISO8859P1) it does not make any difference whether you use VARCHAR2(x BYTE) or VARCHAR2(x CHAR).
It makes only a difference when your DB runs on multi-byte character set (e.g. AL32UTF8 or AL16UTF16). You can simply see it in this example:
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) means you can store up to 1 character, no matter how many byte it has. In case of Unicode one character may occupy up to 4 bytes.
VARCHAR2(1 BYTE) means you can store a character which occupies max. 1 byte.
If you don't specify either BYTE or CHAR then the default is taken from NLS_LENGTH_SEMANTICS session parameter.
Unless you have Oracle 12c where you can set MAX_STRING_SIZE=EXTENDED the limit is VARCHAR2(4000 CHAR)
However, VARCHAR2(4000 CHAR) does not mean you are guaranteed to store up to 4000 characters. The limit is still 4000 bytes, so in worst case you may store only up to 1000 characters in such field.
See this example (€ in UTF-8 occupies 3 bytes):
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
See also Examples and limits of BYTE and CHAR semantics usage (NLS_LENGTH_SEMANTICS) (Doc ID 144808.1)

To answer you first question:
Yes, it means that 1 byte allocates for 1 character. Look at this example
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>
And to answer your next one:
The difference between varchar2 and varchar :
VARCHAR can store up to 2000 bytes of characters while VARCHAR2 can store up to 4000 bytes of characters.
If we declare datatype as VARCHAR then it will occupy space for NULL values, In case of VARCHAR2 datatype it will not occupy any space.

it means ONLY one byte will be allocated per character - so if you're using multi-byte charsets, your 1 character won't fit
if you know you have to have at least room enough for 1 character, don't use the BYTE syntax unless you know exactly how much room you'll need to store that byte
when in doubt, use VARCHAR2(1 CHAR)
same thing answered here Difference between BYTE and CHAR in column datatypes
Also, in 12c the max for varchar2 is now 32k, not 4000. If you need more than that, use CLOB
in Oracle, don't use VARCHAR

Related

Casting a column value as VARCHAR2() that holds 9 characters (TOPIC: ORACLE SQL & PL for Developers)

I've cast a column value as VARCHAR2(9) in my query to make it as a varchar2() that hold 9 characters.
It's been suggested to me that VARCHAR2(10) works better and should be a solution to any requirement that asks for VARCHAR2 capable of holding 9 characters.
Expert advice?
If you need to hold 9 bytes of characters then use VARCHAR2(9 BYTE).
If you need to hold 9 characters (of any byte width) then use VARCHAR2(9 CHAR).
If you need to hold 10 bytes of characters then use VARCHAR2(10 BYTE).
If you need to hold 10 characters (of any byte width) then use VARCHAR2(10 CHAR).
We can't advise you what to use but if you only want 9 characters then use VARCHAR2(9 BYTE) or VARCHAR2(9 CHAR) (as appropriate for the type of characters you will be storing).
It's been suggested to me that VARCHAR2(10) works better and should be a solution to any requirement that asks for VARCHAR2 capable of holding 9 characters.
I suggest you get that person to explain why they are suggesting adding another character; because if you only need to store 9 characters then specifying a limit of 10 seems to be wrong.
For example:
If you have the table:
CREATE TABLE table_name ( value VARCHAR2(10) );
And try to insert 9 unicode characters (at 3-bytes each):
INSERT INTO table_name ( value )
VALUES ( UNISTR( '\2600\2601\2602\2603\2604\2605\2606\2607\2608' ) );
An exception is raised:
ORA-12899: value too large for column "SCHEMA_NAME"."TABLE_NAME"."VALUE" (actual: 27, maximum: 10)
However:
CREATE TABLE table_name ( value VARCHAR2(9 CHAR) );
INSERT INTO table_name ( value )
VALUES ( UNISTR( '\2600\2601\2602\2603\2604\2605\2606\2607\2608' ) );
Works without error and inserts the 9 unicode characters.
db<>fiddle here

Error in my sql (varchar2)

I have the following error in all my tables where I am using varchar2
error ORA-01438: value larger than specified precision allowed for this column
although I have used characters less than the specified length
Note: I am using oracle apex
According to the screenshot, it is the DEP_ID that raises the error, not DEP_NAME. It seems that you wrongly defined that column in the table. This is what you did:
SQL> create table test (dep_id number(1, 10));
Table created.
SQL> insert into test (dep_id) values (1);
insert into test (dep_id) values (1)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL> insert into test (dep_id) values (0.0000000001);
1 row created.
SQL>
In other words, you set precision to "1" (i.e. allow only one significant digit), while scale is set to "10" (which represents "decimal" digits).
For your sake, in this case set DEP_ID NUMBER, without precision or scale.

Oracle SQL difference between varchar2(n) and varchar2(n char)

Scripts here at work always declare varchar2 columns as varchar2(n char). I do not see any difference and just curious. Thanks!
Based on this resource
Oracle9i and above allow Varchar2 columns to be defined as a number of bytes VARCHAR2(50 BYTE) or a number of characters VARCHAR2(50 CHAR), the latter is useful if the database is ever converted to run a double-byte character set (such as Japanese), you won't have to edit the column sizes. The default measure, normally BYTE, is set with nls_length_semantics.
If you create a column as Varchar2 (50) but only store 10 bytes, then Oracle will only save 10 bytes to disc. This does not mean that you should just create Varchar2 (4000) columns 'just in case the space is needed', that is a really bad idea which will reduce the performance and maintainability of your application.
The syntax is VARCHAR2(n) and VARCHAR2(n BYTE|CHAR)
The default for (n) and (n BYTE) are usually the same. (n CHAR) may not be equivalent to (n|BYTE) or (n) unless you set NLS_LENGTH_SEMANTICS parameter to what you want, CHAR or BYTE. This setting is for character sets that use multibyte characters. Generally not for UTF8, for example.
DO NOT change it, since there is existing code that works.
I would guess that (n) == (n CHAR) == (n BYTE) or your system.

SELECT as much data from CLOB to VARCHAR2 as possible, with multibyte chars in the data

Multi-byte characters had caused me a lot of pain.
Any suggestion for this problem?
I have a CLOB field that might contains some multi-byte characters, and I need to select in SQL and convert this field into a string for downstream process, currently I am using:
SELECT DBMS_LOB.SUBSTR( description, 4000, 1 ) FROM table
But the 4000 in above command is in length of characters, rather than bytes. So I had to change to 3000 to handle any multi-byte characters that might have crept into the data else buffer size error will occur.
The problem is for records that do not contain multibyte character, it might unnecessarily truncated more data than it need to.
(The 4000 is the string limitation, we can/had to live with that.)
Is there a way to do something in equivalent of:
SELECT DBMS_LOB.SUBSTR( description, 4000bytes, 1 ) FROM table
That way I can get as much data out as possible.
Note: I am not allowed to create temp tables/views, not using PL/SQL, only SQL SELECT...
Jeffrey's thinking process is ok, but alchn is also right. Just ran into this same problem and here is my solution. You'll have to be able to create a function though:
Create Or Replace Function clob_substr(p_clob In Clob
,p_offset In Pls_Integer
,p_length In Pls_Integer) Return Varchar2 Is
Begin
Return substrb(dbms_lob.substr(p_clob
,p_length
,p_offset)
,1
,p_length);
End;
/
Here is a demo of it's use:
Select c
,clob_substr(c
,1
,4000)
From (
Select xmlelement("t", rpad('é', 4000, 'é'), rpad('é', 4000, 'é')).extract('//text()').getclobval() c
From dual
);
Maybe truncate the resulting varchar2 with SUBSTR:
SELECT SUBSTRB( DBMS_LOB.SUBSTR( description, 4000, 1 ), 1, 4000) FROM table

How to query a CLOB column in Oracle

I'm trying to run a query that has a few columns that are a CLOB datatype. If i run the query like normal, all of those fields just have (CLOB) as the value.
I tried using DBMS_LOB.substr(column) and i get the error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
How can i query the CLOB column?
This works
select DBMS_LOB.substr(myColumn, 3000) from myTable
When getting the substring of a CLOB column and using a query tool that has size/buffer restrictions sometimes you would need to set the BUFFER to a larger size. For example while using SQL Plus use the SET BUFFER 10000 to set it to 10000 as the default is 4000.
Running the DBMS_LOB.substr command you can also specify the amount of characters you want to return and the offset from which. So using DBMS_LOB.substr(column, 3000) might restrict it to a small enough amount for the buffer.
See oracle documentation for more info on the substr command
DBMS_LOB.SUBSTR (
lob_loc IN CLOB CHARACTER SET ANY_CS,
amount IN INTEGER := 32767,
offset IN INTEGER := 1)
RETURN VARCHAR2 CHARACTER SET lob_loc%CHARSET;
I did run into another condition with HugeClob in my Oracle database. The dbms_lob.substr only allowed a value of 4000 in the function, ex:
dbms_lob.substr(column,4000,1)
so for my HughClob which was larger, I had to use two calls in select:
select dbms_lob.substr(column,4000,1) part1,
dbms_lob.substr(column,4000,4001) part2 from .....
I was calling from a Java app so I simply concatenated part1 and part2 and sent as a email.
If it's a CLOB why can't we to_char the column and then search normally ?
Create a table
CREATE TABLE MY_TABLE(Id integer PRIMARY KEY, Name varchar2(20), message clob);
Create few records in this table
INSERT INTO MY_TABLE VALUES(1,'Tom','Hi This is Row one');
INSERT INTO MY_TABLE VALUES(2,'Lucy', 'Hi This is Row two');
INSERT INTO MY_TABLE VALUES(3,'Frank', 'Hi This is Row three');
INSERT INTO MY_TABLE VALUES(4,'Jane', 'Hi This is Row four');
INSERT INTO MY_TABLE VALUES(5,'Robert', 'Hi This is Row five');
COMMIT;
Search in the clob column
SELECT * FROM MY_TABLE where to_char(message) like '%e%';
Results
ID NAME MESSAGE
===============================
1 Tom Hi This is Row one
3 Frank Hi This is Row three
5 Robert Hi This is Row five
For big CLOB selects also can be used:
SELECT dbms_lob.substr( column_name, dbms_lob.getlength(column_name), 1) FROM foo
Another option is to create a function and call that function everytime you need to select clob column.
create or replace function clob_to_char_func
(clob_column in CLOB,
for_how_many_bytes in NUMBER,
from_which_byte in NUMBER)
return VARCHAR2
is
begin
Return substrb(dbms_lob.substr(clob_column
,for_how_many_bytes
,from_which_byte)
,1
,for_how_many_bytes);
end;
and call that function as;
SELECT tocharvalue, clob_to_char_func(tocharvalue, 1, 9999)
FROM (SELECT clob_column AS tocharvalue FROM table_name);
To add to the answer.
declare
v_result clob;
begin
---- some operation on v_result
dbms_lob.substr( v_result, 4000 ,length(v_result) - 3999 );
end;
/
In dbms_lob.substr
first parameter is clob which you want to extract .
Second parameter is how much length of clob you want to extract.
Third parameter is from which word you want to extract .
In above example i know my clob size is more than 50000 , so i want last 4000 character .
If you are using SQL*Plus try the following...
set long 8000
select ...