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 😉