how to check the size of input to avoid exceed DB column limit - oracle

I have an input field of my page with size=8.
And in the DB, the corresponding column is VARCHAR2(8).
But if I input a string of length 8 with a special ascii character in the field, I will get the following exception.
ORA-12899: value too large for column xxxx (actual: 10, maximum: 8)
I'm trying to catch this in the validator, I check myString.getBytes().length which is also 8.
I know one solution is on DB side that change the column to VARCHAR2(8 CHAR).
Is there another solution that I can check this in the controller?

The error is telling you that you've given 10 bytes but the column only allows 8. I am assuming it's bytes because of your use of the Chinese character set. So, I believe that the column was created as if it were VARCHAR2(8 byte).
If you describe the table, you'll see what's going on. Compare that describe with a describe of this one:
create table x (a varchar2(30), b varchar2(30 byte), c varchar2(30 char));
The code you are executing to obtain the number of bytes is almost correct. Instead of:
myString.getBytes().length /* this probably returns 8 */
you need to execute this:
myString.getBytes("UTF-8").length /* this probably returns 10 */

This should help you, this will return the actual size in Bytes.
SELECT LENGTHB ('é')
FROM DUAL;
Above will return 2. So whatever character you are using, you can specify something like MY_VARCHAR_FIELD VARCHAR2(2 BYTES)

Related

A strange problem with MariaDB text,losing data

In some cases, MariaDB will lose the data of the text field.
My table is
create table tt(
id int(11) AUTO_INCREMENT PRIMARY KEY ,
info text
)
My SQL is
update tt join
(select 'StringValue' as info , 1 as id ) a using(id)
set tt.info = a.info
The StringValue is a string data that more than 65535 bytes;
I can execute this SQL successfully using Java JDBC, but only a few bytes can be written.
For example, StringValue is a String data with 65538 bytes, after executing the SQL, tt.info has only 2 bytes.
My MariaDB version is 10.4.7, innodb_page_size is 16kb.
That seems to be simply this:
UPDATE tt
SET info = 'StringValue'
WHERE id = 1;
But, if the string is bigger than TEXT can hold, it will either give a warning or an error, depending on some setting. Is that what you are asking about? Does the code check for warnings and errors?
If you change the column definition from TEXT to MEDIUMTEXT, the limit is 16MB instead of 64KB. (Both of those numbers are in bytes, not characters.
You say it has 2 bytes -- do they happen to be the last 2 bytes?

Why can't I trim a column of type CHAR?

Like the title says, if a create a table in my DB :
CREATE TABLE TEST
(
FIELD CHAR(20 CHAR) NULL
)
NOLOGGING
NOCOMPRESS
NOCACHE;
Insert this :
Insert into TEST
(FIELD)
Values
('TEST -here are blank spaces- ');
COMMIT;
Then i run the following statement :
UPDATE TEST SET FIELD = TRIM(FIELD);
COMMIT;
but the field still has blank spaces, notice that if I change the data type to varchar2, it works ... does anyone know why?
Thanks!
char is a fixed width data type. A char(20) will always and forever have a length of 20. If you try to insert a shorter string, it will be padded with spaces to the fixed width length of the field. So
UPDATE TEST SET FIELD = TRIM(FIELD);
removes the spaces due to the trim function, then adds them back because the string that gets written has to be exactly 20 bytes long.
Practically, there is almost never a case to use char. You're almost always better off with a varchar2. varchar2 is a variable length data type so there is no need for the database to append the spaces to the end.

ORA-12899 Error Too large String for Same column but success different tables

I am updating string to column of length 35 into two tables
first table update was success but second table give ORA error ORA-12899 Error Too large String
select length('Andres Peñalver D1 Palmar Sani salt') bytes from dual;
BYTES
----------
35
select lengthb('Andres Peñalver D1 Palmar Sani salt') bytes from dual;
BYTES
----------
36
Both tables colm1 field declared as VARCHAR(35), first table update fails and second one success.
update t
set colm1='Andres Peñalver D1 Palmar Sani Salt'
where value1='123456';
update t2
set colm1='Andres Peñalver D1 Palmar Sani Salt'
where value1='123456';
ORA-12899
select value from nls_database_parameters where parameter='NLS_CHARACTERSET';
VALUE
----------------------------------------------------------------
AL32UTF8
let me know why this behaviour for these table which is having same column type
Check the actual columns size for both the tables in all_tab_columns.
35 Char is 3 times 35 bytes, and if one table's column is defined in char other in byte(during ddl) the size is different.
Normal characters like A-Z a-z take 1 byte to store but language specific characters take 3 byte to store.
The full error message as described in the error message documentation
should give you the answer:
$ oerr ora 12899
12899, 00000, "value too large for column %s (actual: %s, maximum: %s)"
// *Cause: An attempt was made to insert or update a column with a value
// which is too wide for the width of the destination column.
// The name of the column is given, along with the actual width
// of the value, and the maximum allowed width of the column.
// Note that widths are reported in characters if character length
// semantics are in effect for the column, otherwise widths are
// reported in bytes.
// *Action: Examine the SQL statement for correctness. Check source
// and destination column data types.
// Either make the destination column wider, or use a subset
// of the source column (i.e. use substring).
This is likely linked to character length semantics.

SQL loader position

New to SQL loader and am a bit confused about the POSITION.
Let's use the following sample data as reference:
Munising 49862 MI
Shingleton49884 MI
Seney 49883 MI
And here is the load statement:
LOAD DATA
INFILE 'zipcodes.dat'
REPLACE INTO TABLE zipcodes (
city_name POSITION(1) CHAR(10),
zip_code POSITION(*) CHAR(5),
state_abbr POSITION(*+1) CHAR(2)
)
In the load statement, the city_name POSITION is 1. How does SQLLDR know where it ends? Is CHAR(10) the trick here? Counting the two spaces behind 'Munising', it has 10 characters.
Also why is zip_code assigned with CHAR even though it contains nothing but numbers?
Thank You
Yes, when end position is not specified, it is derived from the datatype. This documentation explains the POSITION clause.
city_name POSITION(1) CHAR(10)
Here the starting position of data field is 1. Ending position is not specified, but is derived from the datatype, that is 10.
zip_code POSITION(*) CHAR(5)
Here * specifies that, data field immediately follows the previous field and should be 5 bytes long.
state_abbr POSITION(*+1) CHAR(2)
Here +1 specifies the offset from the previous field. Sqlloader skips 1 byte and reads next 2 bytes, as derived from char(2) datatype.
As to why zipcode is CHAR, zip code is considered simply a fixed length string. You are not going to do any arithmetic operations on it. So, CHAR is appropriate for it.
Also, have a look at SQL Loader datatypes. In control file you are telling SQL*Loader how to interpret the data. It can be different from that of table structure. In this example you could also specify INTEGER EXTERNAL for zip code.
we need three text file & 1 batch file for Load Data:
Suppose your file location 'D:\loaddata'
input file 'D:\loaddata\abc.CSV'
1. D:\loaddata\abc.bad -- empty
2. D:\loaddata\abc.log -- empty
3. D:\loaddata\abc.ctl "Write Code Below"
OPTIONS ( SKIP=1, DIRECT=TRUE, ERRORS=10000000, ROWS=5000000)
load data
infile 'D:\loaddata\abc.CSV'
TRUNCATE
into table Your_table
(
a_column POSITION (1:7) char,
b_column POSITION (8:10) char,
c_column POSITION (11:12) char,
d_column POSITION (13:13) char,
f_column POSITION (14:20) char
)
D:\loaddata\abc.bat --- For execution
sqlldr db_user/db_passward#your_tns control=D:\loaddata\abc.ctl log=D:\loaddata\abc.log
After double click "D:\loaddata\abc.bat" file you data will be load desire oracle table. if anything wrong check you "D:\loaddata\abc.bad" and "D:\loaddata\abc.log" file

How to make a varchar2 field shorter in Oracle?

I have a field in a table that is varchar2, 4000 bytes. There are over 50000 rows. Not all rows have data in this field. Few data fields are over 255 bytes, but some are 4000. To place the table in a new application, I need to shorten the field to 255 bytes.
Is there a SQL statement that will reduce the length to 255? I realize data will be lost, that is part of the cost of the new application. The cut should be arbitrary, just stopping the data at 255 no matter the circumstance.
update b set text2 = substr(text2,1,255);
then alter table to set length of column to 255 :
alter table b MODIFY "TEXT2" varchar2(255 byte);

Resources