ORA-12899 value too large for column despite of same length - sql

I am running the following query. But getting ORA-12899. Altough the length of string am trying to insert is 30.
INSERT INTO TABLE1 SELECT * FROM temp_Table1 where LENGTH(column1)=30;
SQL Error: ORA-12899:value too large for column "TABLE1"."column1" (actual: 31, maximum: 30)
select column1 from temp_Table1 where LENGTH(column1)=30;
Testing  - HLC/TC Design Corre
Desc temp_Table1
column1 VARCHAR2(30)
Desc Table1
column1 VARCHAR2(30)

You're seeing the difference between character and byte length semantics:
You must specify a maximum length for a VARCHAR2 column. This maximum must be at least 1 byte, although the actual string stored is permitted to be a zero-length string (''). You can use the CHAR qualifier, for example VARCHAR2(10 CHAR), to give the maximum length in characters instead of bytes. A character is technically a code point of the database character set. You can use the BYTE qualifier, for example VARCHAR2(10 BYTE), to explicitly give the maximum length in bytes. If no explicit qualifier is included in a column or attribute definition when a database object with this column or attribute is created, then the length semantics are determined by the value of the NLS_LENGTH_SEMANTICS parameter of the session creating the object.
If your session is using byte semantics then the column in your table will default to that:
select value from nls_session_parameters where parameter = 'NLS_LENGTH_SEMANTICS';
VALUE
----------------------------------------
BYTE
create table t42(text varchar2(5));
Table T42 created.
select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';
C
-
B
That is the same as explicitly doing:
create table t42(text varchar2(5 byte));
If your source data is five characters but includes any multibyte characters then the number of bytes will exceed five:
insert into t42 (text) values ('Hello');
1 row inserted.
insert into t42 (text) values ('Señor');
SQL Error: ORA-12899: value too large for column "SCHEMA"."T42"."TEXT" (actual: 6, maximum: 5)
Which is what you're seeing. When you insert the values from your other table you are filter on the length of the values, but length() counts characters rather than bytes. There is a lengthb() function that does count bytes. If you check the byte length of the 30-character value you're selecting you'll see it is in fact 31 bytes, so one of those characters is multibyte.
with t42 (text) as (
select 'Hello' from dual
union all select 'Señor' from dual
union all select 'Testing  - HLC/TC Design Corre' from dual
)
select text, length(text) as chars, lengthb(text) as bytes, dump(text, 16) as hex
from t42;
TEXT CHARS BYTES HEX
------------------------------- ----- ----- ----------------------------------------------------------------------------------------------------------
Hello 5 5 Typ=1 Len=5: 48,65,6c,6c,6f
Señor 5 6 Typ=1 Len=6: 53,65,c3,b1,6f,72
Testing  - HLC/TC Design Corre 30 31 Typ=1 Len=31: 54,65,73,74,69,6e,67,c2,a0,20,2d,20,48,4c,43,2f,54,43,20,44,65,73,69,67,6e,20,43,6f,72,72,65
From the dump() values you can see that after Testing (54,65,73,74,69,6e,67) and before the space and dash (20,2d) you have c2,a0, which is the UTF-8 multibyte non-breaking space character. (You often see that, along with curly quotes and other non-ASCII-range characters, in text that has been copied from,. say, a Word document).
You can either change your insert to filter on LENGTHB(column1)=30 (which will exclude the row you currently find), or change your column definition to 30 characters instead of 30 bytes:
drop table t42;
Table T42 dropped.
create table t42(text varchar2(5 char));
Table T42 created.
select char_used from user_tab_columns where table_name = 'T42' and column_name = 'TEXT';
C
-
C
insert into t42 (text) values ('Hello');
1 row inserted.
insert into t42 (text) values ('Señor');
1 row inserted.
Or replace any unexpected multibyte characters with single-byte equivalents, if that's possible and makes sense for your data; in this case a normal space might work, but with any substitution you are destroying information that might actually be important.

Try to change your table like
ALTER TABLE1 MODIFY column1 VARCHAR2(30 CHAR)
The error states that your column1 can store maximum of 30 characters and you are passing more than 30 characters in it which results in the error.
You can also refer this article: Oracle Database - Bytes or Characters for VARCHAR2 and CHAR

ORA-12899
Often times, as our companies grow and evolve in response to an
expansion in the form of client-base, staff, profit or markets, the
data associated with this growth will also change. Data systems like
Oracle have the innate ability to remain fairly flexible in regards to
working with this variance in information. Still, even the most
versatile database systems require maintenance and refining in the
face of increased data traffic. This work is essential to
accommodating any constraints on memory or necessary redefinitions of
parameters. The ORA-12899 error is representative of an instance in
which either an uptick in data or a user error is forcing Oracle to
stall during its requested action.
THE PROBLEM
The ORA-12899 is an Oracle error that occurs when the value entered
into the column string is too large. What this means is that an
attempt was made by the user to update or insert a column with a value
that is too wide for the destination column. The name of a particular
column will be given and the actual width of the value, as well as the
maximum width permitted for the column, will be associated with that.
As mentioned, the value can be given in the form of characters. In the
event that the width is reported in characters, this will mean that
character length semantics are operating for the column. Otherwise the
width will be reported in bytes. Essentially, this error results from
trying to push through a value, or set of values, that exceed the
specified maximum width of the column. So, how does a user correct
this type of error?
THE SOLUTION
To begin, open up the OERR utility. The user will require the full
ORA-12899 message to receive the proper feedback on the error. This
will provide more information on the error and allow further
investigation. Typically, the error can come from one of three
sources. The first source is the SQL statements that have been
generated. Checking source and destination column data types to
discover whether they are compatible with current formats is the
second source. Lastly, the user can look at the destination column
width – where the value is being assigned – to make sure it is large
enough to accommodate the maximum value that the user anticipates
assigning. Let us now turn to an example that corrects ORA-12899.
Suppose the user has created the following table:
CREATE TABLE Clients(
ClientID varchar2(9) PRIMARY KEY,
Client_Contact varchar2(40) NOT NULL,
Address varchar(20) NOT NULL,
Zip varchar2(5) NOT NULL,
Client_Number varchar2(11) NOT NULL)
The user then attempts to issue an INSERT VALUES statement that looks
something like this:
INSERT INTO Clients VALUES(
727546345,
‘Roger Holcomb’,
‘—Benjamin Road Syracuse’,
‘-----‘, 05307623754)
The user might try to run the statement from here, but will receive
the following error message:
Error starting at line 7 in command: INSERT INTO Clients
VALUES(727546345, ‘Ricky Galorey’, ‘18 Benjamin Road Syracuse’,
‘13208’, 05307623754) Error report: SQL Error: ORA-12899: value too
large for column “ORGANIZATIONS”. “MARKET”. “ADDRESS”(actual: 25,
maximum: 20) 12899. 00000 – “value too large for column %s (actual:
%s, maximum: %s)”
This error statement indicates that the variable ‘Address’ cannot hold
more than twenty characters as that would exceed the width of the
column parameter. When we look back at the address value (’18 Benjamin
Road Syracuse’) we can see that the total number of characters (25)
exceeds the maximum number allowed for the width of the column. To
correct this, the user can change the VARCHAR2 for address to an
amount that can accommodate the typical address length that their
company would input.
The above answer original URL

Due to different NLS settings in the target table database it might require more bytes in the target.
Try altering the table as
alter Table1 modify column1 varchar2(30 char)

Related

Avoid inserting exponential value in DB Float column

I have a table like
CONTACT
Name Null Type
------------------------------ -------- -----------
CONTACT_ID NOT NULL NUMBER
NAME NOT NULL VARCHAR2(45)
EMAIL NOT NULL VARCHAR2(45)
ADDRESS NOT NULL VARCHAR2(45)
TELEPHONE NOT NULL VARCHAR2(45)
AMOUNT NOT NULL FLOAT(126)
and the insert statement is:
Insert into contact("CONTACT_ID","NAME","EMAIL","ADDRESS","TELEPHONE","AMOUNT")
values ('36','babusailesh1117777','hainatu1#gmail.com','Vietnam1',
'0904277091','0.0000000555559080767');
When I see the final value inserted in the database, I see an exponential value.
How can I avoid this at database level for all tables?
It isn't stored as an exponential, it's stored in Oracle's internal number representation. When you query it, it's displayed with your sessions's current number format:
select 0.0000000555559080767 from dual;
0.0000000555559080767
---------------------------------------
5.6E-08
Which you can override in SQL*Plus or SQL Developer:
set numformat 999.9999999999999999999
select 0.0000000555559080767 from dual;
0.0000000555559080767
------------------------
.0000000555559080767
Or explicitly format the value as a string, for display only:
set numf ""
select to_char(0.0000000555559080767, '9990.9999999999999999999') from dual;
TO_CHAR(0.000000055555908
-------------------------
0.0000000555559080767
If you have a client application retrieving and using the value then it should query it as a float, into a suitable data type for the client's language, and then it's up to the client how it's displayed.
You also shouldn't be inserting a string into the float column, that just does an implicit conversion; the last argument in your insert should be 0.0000000555559080767 rather than the quoted '0.0000000555559080767'.
This is a function of the way the value is displayed, not what is being stored in the database. The database just stores a numeric float value, and whatever retrieves and displays the data decides how to display that. The exponential value you mention is common for displaying such floating point numbers.
You can have Oracle return a string formatted in a way for display using a function such as to_char, that allows you to set formatting. However, it may make more sense to handle this in whatever program or code is using the database.
Also note that floating point numbers have limited precision, so if you need to get that exact number string back, a float is not the way to go.

How to restrict the length of INTEGER when creating a table in SQL Server?

When creating a table in SQL SERVER, I want to restrict that the length of an INTEGER column can only be equal 10.
eg: the PhoneNumber is an INTEGER, and it must be a 10 digit number.
How can I do this when I creating a table?
If you want to limit the range of an integer column you can use a check constraint:
create table some_table
(
phone_number integer not null check (phone_number between 0 and 9999999999)
);
But as R.T. and huMpty duMpty have pointed out: a phone number is usually better stored in a varchar column.
If I understand correctly, you want to make sure the entries are exactly 10 digits in length.
If you insist on an Integer Data Type, I would recommend Bigint because of the range limitation of Int(-2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647))
CREATE TABLE dbo.Table_Name(
Phone_Number BIGINT CONSTRAINT TenDigits CHECK (Phone_Number BETWEEN 1000000000 and 9999999999)
);
Another option would be to have a Varchar Field of length 10, then you should check only numbers are being entered and the length is not less than 10.
I would recommend you to use varchar as phone number(only for phone numbers as some phone numbers may contain hyphen,phus sign) and restrict the length to 10 ie, varchar(10).
As correctly pointed by a_horse_with_no_name in comments you can put constraint on the numbers to be of specified range like this:
check (phone_number between 0 and 9999999999)
Also on a side note:-
You will receive a error message like this if you use numbers outside the range of int -2147483648 through 2147483647
Arithmetic overflow error converting expression to data type int.
So you will not be able to use all the int of length 10 in your case.
As per me Phone number should not be stored in integer as we are not going to do any numeric operation on it like adding dividing .we are going to treat it as string for e.g. finding all number with ISD say '91' or STD '022' etc secondly if you switch to make it integer you have to handle overflow
I don't think there is a way to limit if you use number fields like int, bigint, smallint, and tinyint
Make a varchar(10) field and validate before insert
Still you need to use int field to store the phone number, you will need to restrict before in your application
Make column varchar and create a check that it strictly should have 10 characters
create table some_table
(
phone_number varchar(10) check (len(phone_number)=10)
);
First consider internal and external format:
Yes, a telephone number can be stored as an integer. You would have to assure however that all numbers are stored in the same format, e.g. as the international number without the plus sign. 4940123456 would then be a German number for instance, as 49 is the German country code. To analize the number later, however, would be difficult; country codes can be 1 to 4 digits, followed by a presumably unknown number of area code digits. But just to know a number and not to know its structure may be sufficient for your purposes. With check constraints you could assure that the number is positive and not longer than, well, how long is the longest number allowed? Be aware: Everytime you show the number, you may have to format the output (in the example given: add a leading plus sign to the number).
The other way would be to store phone numbers as strings. That would make it possible to store numbers such as '+49-40-123456'. Then the internal format is the same as the external. Advantage: You wouldn't have to think of formatting the output everytime you show the number. But you could even change the format on output if you wanted (remove dashes or replace the plus sign with the actual county dial code or remove country and area code for local calls, etc.) You would have to decide whether to enforce a certain format or not. If not, then numbers could look very different '123456', '004940123456', '040/123456', ... To enforce a certain format, you would write a function (because of the complexity of such a format) and use that in a check constraint. Or write an insert trigger (this should be a BEFORE INSERT trigger, because you want to change a value; as T-SQL doesn't provide this, you would use an INSTEAD OF INSERT trigger instead) to have the field formatted as you desire.
My recommendation is:
CREATE TABLE trial_table (phone_number VARCHAR(13));
The column can be used for international numbers too.

Determining Nvarchar length

I've read all about varchar versus nvarchar. But I didn't see an answer to what I think is a simple question. How do you determine the length of your nvarchar column? For varchar it's very simple: my Description, for example, can have 100 characters, so I define varchar(100). Now I'm told we need to internationalize and support any language. Does this mean I need to change my Description column to nvarchar(200), i.e. simply double the length? (And I'm ignoring all the other issues that are involved with internationalization for the moment.)
Is it that simple?
Generally it is the same as for varchar really. The number is still the maximum number of characters not the data length.
nvarchar(100) allows 100 characters (which would potentially consume 200 bytes in SQL Server).
You might want to allow for the fact that different cultures may take more characters to express the same thing though.
An exception to this is however is if you are using an SC collation (which supports supplementary characters). In that case a single character can potentially take up to 4 bytes.
So worst case would be to double the character value declared.
From microsoft web site:
A common misconception is to think that NCHAR(n) and NVARCHAR(n), the n defines the number of characters. But in NCHAR(n) and NVARCHAR(n) the n defines the string length in byte-pairs (0-4,000). n never defines numbers of characters that can be stored. This is similar to the definition of CHAR(n) and VARCHAR(n).
The misconception happens because when using characters defined in the Unicode range 0-65,535, one character can be stored per each byte-pair. However, in higher Unicode ranges (65,536-1,114,111) one character may use two byte-pairs. For example, in a column defined as NCHAR(10), the Database Engine can store 10 characters that use one byte-pair (Unicode range 0-65,535), but less than 10 characters when using two byte-pairs (Unicode range 65,536-1,114,111). For more information about Unicode storage and character ranges, see
https://learn.microsoft.com/en-us/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver15
#Musa Calgar - exactly right. That link has the information for the answer to this question.
But to make sure the question itself is clear, we are talking about the 'length' attribute we see when we look at the column definition for a given table, right? That is the storage allocated per column. On the other hand, if we want to know the number of characters for a given string in the table at a given moment you can:
"SELECT myColumn, LEN(myColumn) FROM myTable"
But if the storage length is desired, you can drag the table name into the query window using SSMS, highlight it, and use 'Alt-F1' to see the defined lengths of each column.
So as an example, I created a table like this specifiying collations. (Latin1_General_100_CI_AS_SC allows for supplemental characters - that is, characters that take more than just 2 bytes):
CREATE TABLE [dbo].[TestTable1](
[col1] [varchar](10) COLLATE Latin1_General_100_CI_AS,
[col2] [nvarchar](10) COLLATE Latin1_General_100_CI_AS_SC,
[col3] [nvarchar](10) COLLATE Latin1_General_100_CI_AS
) ON [PRIMARY]
The lengths show up like this (Highlight in query window and Alt-F1):
Column_Name Type Length [...] Collation
col1 varchar 10 Latin1_General_100_CI_AS
col2 nvarchar 20 Latin1_General_100_CI_AS_SC
col3 nvarchar 20 Latin1_General_100_CI_AS
If you insert ASCII characters into the varchar and nvarchar fields, it will allow you to put 10 characters into all of them. There will be an error if you try to put more than 10 characters into those fields:
"String or binary data would be truncated.
The statement has been terminated."
If you insert non-ASCII characters like 'ā' you can still put 10 of them into each one, but SQL Server will convert the values going into col1 to the closest known character that fits into 1-byte. In this case, 'ā' will be converted to 'a'.
However, if you insert characters that require 4 bytes to store, like for example, '𠜎', you will only be allowed to put FIVE of them into the varchar and nvarchar fields. Any more than that will result in the truncation error shown above. The varchar field will show question marks because it has no single-byte character that it can convert that input to.
So when you insert five of these '𠜎', do a select of that row using len(<colname>) and you will see this:
col1 len(col1) col2 len(col2) col3 len(col3)
?????????? 10 𠜎𠜎𠜎𠜎𠜎 5 𠜎𠜎𠜎𠜎𠜎 10
So the length of col2 shows 5 characters since supplemental characters were defined when the table was created (see above CREATE TABLE DDL statement). However, col3 did not have _SC for its collation, so it is showing length 10 for the five characters we inserted.
Note that col1 has ten question marks. If we had defined the col1 varchar using the _SC collation instead of the non-supplemental one, it would behave the same way.

Impact on changing the data type from char to varchar2

Can anyone tell me will there be any impact on changing the datatype of a column from char to varchar2.
Because the issue i am facing is when i fire a select query i.e
select * from table_name where column_name in ('X','Y','Z');
The above query is returning only few rows. And recently the column_name data type was changed from char to varchar. The rows returned are the rows after the data type was changed.
A varchar2 datatype, when stored in a database , uses only the space allocated to
it. If you have a varchar2(100) and put 50 bytes in the table, it will use 52 bytes
(leading length byte).
A char datatype, when stored in a database table, always uses the maximum length and is
blank padded. If you have char(100) and put 50 bytes into it, it will consume 102
bytes.
So in your case probably its only giving the rows from the space allocated to varchar and hence only few rows are returned i believe.
Refered from : http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1542606219593

Entering special characters fails in Oracle table

I need to test if my application is reading special characters from the database and displaying them in exactly the same way. For this, I need to populate the database table with all special characters available. However, I am not sure how I can specify the special characters in the sql insert query. Can anyone please guide me to an example where I can insert a special character in the query? For simplicity sake, suppose the table is a City table with Area and Avg_Temperature being the 2 columns. If I need to insert the degree (celcius/farhenheit) symbol in Avg_Temperature column, how should I write the query?
*[Edit on 1/9/2012 at 2:50PM EST]*As per Justin Cave's suggestion below, I did following analysis:
Table: create table city(area number, avg_temperature nvarchar2(10));
Date: insert into city values (1100, '10◦C');
Query:
select dump(avg_temperature, 1010) from city where area = 1100;
O/P
DUMP(AVG_TEMPERATURE,1010)
----------------------------------------------------------
Typ=1 Len=8 CharacterSet=AL16UTF16: 0,49,0,48,0,191,0,67
Query
select value$ from sys.props$ where name='NLS_CHARACTERSET';
O/P
VALUE$
----------------
WE8MSWIN1252
Query:
select value$ from sys.props$ where name='NLS_NCHAR_CHARACTERSET';
O/P
----------------
AL16UTF16
It seems that the insert does mess up the special characters as Justin Cave suggested. But I am not able to understand why this is happening? Can anyone please provide related suggestion?
First you should not store the symbol as part of your column. That requires you to declare the column as VARCHAR which will give you lots of problems in the long run (e.g. you cannot sum() on them, you cannot avg() on them and so on)
You should store the unit in which the temperature was taken in a second column (e.g. 1 = celcius and 2 = fahrenheit) and translate this when displaying the data in the frontend. If you really want to store the symbol, declare the units columns as CHAR(1):
CREATE TABLE readings
(
area number(22),
avg_temperature number(10,3),
units varchar(2)
)
Then you can insert it as follows:
INSERT INTO readings
(area, avg_temperature, units)
VALUES
(1000, 12.3, '°C');
But again: I would not recommend to store the actual symbol. Store only the code!
First you need to know what the database character set is. Then you need to know what character set your "client" connection is using. Life is always easier if these are the same.
If your databse is utf-8 and your client is utf-8 then you don't need to do any character escaping you can just use the utf-8 encoding for the desired character.
In your example the degree character is unicode codepoint u+00b0.
In utf-8 this is a two-byte sequence: x'c2', x'b0'.