Exploring Oracle and MySQL data type`s behaviour (int, varchar)

Daha bir mənimçün maraqlı mövzuya toxunacıq.
Qısa olaraq bir cədvəl yaradacıq o cədvələ məlumatlar daxil edəcik və bu əsnada əldə etdiyimiz nəticələrə error-lara baxacıq.

Müqayisə zamanı çox faydalı aşağıdakı cədvəlimizdən istifadə edəcik:

Başlayırıq Oracle-dan və 2 column-lu cədvəlimizi yaradırıq:

-- Oracle

-- MySQL syntax ilə cədvəl yaratmaq

create table data_type_test(
id int,
firstname varchar(25)
);

>>>table DATA_TYPE_TEST created.

Lakin bu bizi aldatmasın faktiki olaraq Oracle internal olaraq bütün numeric-ləri NUMBER tipində saxlayır. Bundan əlavə varchar() yazdığmız da internal olaraq varchar2() şəklində saxlanılacaq. Sübut:

desc data_type_test;

Name      Null Type
--------- ---- ------------
ID             NUMBER(38)
FIRSTNAME      VARCHAR2(25)

Burdan bir daha görürük ki, Oracle-da İNT\İNTEGER = NUMBER(38). Yəni 38 uzunluqda bir rəqəmə.
Qeyd edək ki, İNT=İNTEGER və aşağıdakı yazılış da düzgündür.

-- Oracle

create table data_type_test(
id int,
firstname varchar(25)
);

>>>table DATA_TYPE_TEST created.

desc data_type_test;

Name      Null Type
--------- ---- ------------
ID             NUMBER(38)
FIRSTNAME      VARCHAR2(25)

Burda MySQL-çilər üçün çaşqınlıq yaranır. Çünki biz öyrəşmişik belə qəbul edək ki, unsigned İNT 10 uzunluqda bir ədəd qəbul edir.
Yəni:

-- MySQL

create table data_type_test(
id int unsigned,
firstname varchar(25)
);

mysql> show create table data_type_test;
CREATE TABLE `data_type_test` (
`id` int(10) unsigned DEFAULT NULL,
`firstname` varchar(25) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Gördüyümüz kimi MySQL-in İNTEGER-i Oracle-in İNTEGER-i deyil 🙂
Faktiki olaraq Oracle-da İnteger tipi yoxdur onun yerine Number var. Bu yəqin ki, uyğunluq məqsədli əlavə olunub.

Əgər biz Oracle-da məhz MySQL-in İNT-ini təyin etmək istəsək o zaman NUMBER(10,0) şəklində qeyd edə bilərik. Və yaxud da əgər unsigned istifadə etməsək MySQL-də int(11) = NUMBER(11,0).
Sınayaq:

-- MySQL

create table data_type_test(
id int,
firstname varchar(5)
);

mysql> show create table data_type_test;
CREATE TABLE `data_type_test` (
`id` int(11) DEFAULT NULL,
`firstname` varchar(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
-- Oracle

create table data_type_test(
id number(11,0),
firstname varchar2(5)
);

desc data_type_test;

Name      Null Type
--------- ---- -----------
ID             NUMBER(11)
FIRSTNAME      VARCHAR2(5)

Bəli istədiyimiz nəticəni əldə etmiş olduq.

İndi isə gəlin bəzi məlumatlar daxil edək. Bilərəkdən 11-dən daha uzun bir ədəd daxil edək:

-- Oracle

insert into data_type_test(id,firstname) values(12345678901233454, 'aze');
>>>
Error starting at line : 23 in command -
insert into data_type_test(id,firstname) values(12345678901233454, 'aze')
Error report -
SQL Error: ORA-01438: value larger than specified precision allowed for this column
01438. 00000 -  "value larger than specified precision allowed for this column"
*Cause:    When inserting or updating records, a numeric value was entered
that exceeded the precision defined for the column.
*Action:   Enter a value that complies with the numeric column's precision,
or use the MODIFY option with the ALTER TABLE command to expand
the precision.

Dahiyanə məhz bizim gözlədiyimiz kimi 😉
Qeyd edim ki, Oracle 11g R2 default installation-dan sonrakı istifadədir.
Həmçinin MySQL 5.5.34-üm də default config faylı ilə çalışır

Eyni test-i MySQL-də edək:

mysql> insert into data_type_test(id,firstname) values(12345678901233454, 'aze');
Query OK, 1 row affected, 1 warning (0.06 sec)

1 warning olaraq göstərir. Baxaq:

mysql> show warnings;
+---------+------+---------------------------------------------+
| Level   | Code | Message                                     |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'id' at row 1 |
+---------+------+---------------------------------------------+
1 row in set (0.00 sec)

Çox gözəl lakin bir dəqiqə out of range value insert etməyə çalışmağımıza baxmayaraq insert
uğurlu olub )) Gələn nəticənin isə bizim insert-imizdəki value ilə uzaqdan yaxından heç bir əlaqəsi yoxdur.

mysql> select * from data_type_test;
+------------+-----------+
| id         | firstname |
+------------+-----------+
| 2147483647 | aze       |
+------------+-----------+
1 row in set (0.00 sec)

12345678901233454 və 2147483647
Hansı əsasla belə bir şey edib, naməlumdur.

Gəlin testimizi davam etdirək və bu dəfə də varchar2\varchar column üçün 5-dən böyük string insert edək:

-- Oracle

insert into data_type_test(id,firstname) values(1234567, 'shahriyar');

>>>
Error starting at line : 25 in command -
insert into data_type_test(id,firstname) values(1234567, 'shahriyar')
Error report -
SQL Error: ORA-12899: value too large for column "HR"."DATA_TYPE_TEST"."FIRSTNAME" (actual: 9, maximum: 5)
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).

Həqiqətən də super.
Eyni test MySQL-də:

-- MySQL

mysql> insert into data_type_test(id,firstname) values(1234567, 'shahriyar');
Query OK, 1 row affected, 1 warning (0.06 sec)

mysql> show warnings;
+---------+------+------------------------------------------------+
| Level   | Code | Message                                        |
+---------+------+------------------------------------------------+
| Warning | 1265 | Data truncated for column 'firstname' at row 1 |
+---------+------+------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from data_type_test;
+------------+-----------+
| id         | firstname |
+------------+-----------+
| 2147483647 | aze       |
|    1234567 | shahr     |
+------------+-----------+
2 rows in set (0.00 sec)

Uppss. Bu halda isə MySQL sadəcə string-in ilk 5 character-ini saxladı digərlərini truncate elədi.

Təbii ki, DEFAULT MySQL installation-dan sonrakı bu hal heç bir məntiqə və əsasa sığmır.
Hər hansı səhv məlumatın bazaya daxil edilməsinin qarşısı mütləq şəkildə alınmalıdır.

Bəs necə edək ki MySQL də Oracle kimi ERROR-lar versin və biz xəbərdar etsin?

Bu məqsədlə biz my.cnf config faylında [mysqld] kataloq altına
sql_mode = TRADİTİONAL
sətrini qeyd edirik, MySQL-ə restart veririk.

-- 1
root@sh-v3:~# nano /etc/mysql/my.cnf
.
-- 2
[mysqld]
sql_mode = TRADİTİONAL

-- 3
root@sh-v3:~# service mysql restart
mysql stop/waiting
mysql start/running, process 7892

Və yuxarıdakı insert-ləri bir daha sınayaq:

mysql> insert into data_type_test(id,firstname) values(12345678901233454, 'aze');
ERROR 1264 (22003): Out of range value for column 'id' at row 1

Necə gözəl bir error.

Daha biri:

mysql> insert into data_type_test(id,firstname) values(1234567, 'shahriyar');
ERROR 1406 (22001): Data too long for column 'firstname' at row 1

Məqsədimizə çatmış hesab olunuruq.
Təşəkkürlər 😉

Səs: +20. Bəyənilsin Zəifdir

Müəllif: Şəhriyar Rzayev

Şərh yazın