Arxiv

Archive for İ

Constraints in Oracle and MySQL

Constraint-lər bizə business qaydalarımızı cədvəllərimizdə təyin etməyə kömək edən vasitələrdir.
Sadə dillə izah etməyə çalışsaq məsələn,
Deyək ki, bizim bussines qaydamız tələb edir ki, bütün soyadlar təkrarsız olsun, bütün date-lər yalnız 2013-cü ildən böyük olsun, və yaxud da bütün istifadəçi yaşları yalnız 23-dən böyük olsun və.s
Bu kimi istəklərimizi cədvəldə constraintlər yaratmaqla həll etmiş oluruq. və yalnız bizim bu business rule-a uyğun gələn data-lar cədvələ daxil edilə biləcək.

Oracle-da aşağıdakı constraint-lər var:

UNİQUE
NOT NULL
PRİMARY KEY
FOREİGN KEY
CHECK

UNİQUE:

UNİQUE constraint adından da göründüyü kimi, ya 1 column ya da column qruplarının unikal məlumatlarla doldurulmasını təmin edir. Dolayısı ilə 1 dəfə daxil edilən məlumat 2ci dəfə ora düşə bilməz. Öz işinə görə PRİMARY KEY-ə bənzəyən UNİQUE-ın yeganə fərqi NULL datanın daxil edilməsinə icazə verməsidir. Burdan belə nəticə çıxır ki, NULL unikal sayılmır, həmçinin sonsuz sayda NULL insert etmək olar.
Burdan daha bir nəticə çıxır ki, PK(primary key) = unique + not null.

Digər tərəfdən onu da qeyd etməliyik ki, unique constraint təyin edilmiş column-lar index-li olur. Yəni, unique constraint yaradıldıqda, Oracle column-da index-in olub olmadığına baxacaq. Əgər index tapılmasa onu avtomatik olaraq yaradacaq.
Daha bir dolayı nəticəmiz bundan ibarətdir ki, unique = index + constraint.

UNİQUE ilə bağlı daha bir məlumatı da verməliyik ki, B*TREE index-lər NULL-u əhatə etmir.
Burdan belə nəticə çıxarırıq ki əgər biz cədvəldə NULL məlumat axtarsaq index istifadə olunmayacaq bu da full table scan-a gətirib çıxardacaq. Full scan ise performance killer hesab olunur.

Teorik məlumatdan sonra keçək praktikaya:

-- Oracle

-- UNİQUE

-- Syntax 1

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
unique key(id)
);

>>>
Error report -
SQL Error: ORA-00906: missing left parenthesis
00906. 00000 -  "missing left parenthesis"
*Cause:    
*Action:

-- Syntax 2

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
unique(id)
);

>>>
table T20 created.

-- Syntax 3

create table t20(
id number unique,
firstname varchar2(15),
lastname varchar2(15)
);

>>>
table T20 created.

Yuxarıdakı 3 syntax-dan 2si Oracle-da dəstəklənir.
İndi isə yaranmış constraint haqqında məlumatları əldə etmək üçün kiçik sorğudan istifadə edək.

— Oracle

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
SYS_C0011585	U

SYS_C0011585 = unique constraint-in internal generate olunan adıdır.

Əgər spesifik ad vermək istəyiriksə ki bu çox faydalı hesab olunur:

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
constraint id_unikal unique(id)
);

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
ID_UNIKAL	U

İndi isə eyni testləri MySQL-də edək.

-- MySQL

-- Syntax 1

mysql> create table t20(
    -> id int,
    -> firstname varchar(15),
    -> lastname varchar(15),
    -> unique key(id)
    -> );
Query OK, 0 rows affected (0.09 sec)

-- Syntax 2

mysql> create table t20(
    -> id int,
    -> firstname varchar(15),
    -> lastname varchar(15),
    -> unique(id)
    -> );
Query OK, 0 rows affected (0.11 sec)

-- Syntax 3

mysql> create table t20(
    -> id int unique,
    -> firstname varchar(15),
    -> lastname varchar(15)
    -> );
Query OK, 0 rows affected (0.11 sec)

Hər 3 syntax dəstəklənir.
Oracle-da constraint metadatanı oxumağı göstərdik indi də MySQL üçün göstərək.

-- MySQL

-- 1ci usul 

mysql> show create table t20;
>>>
CREATE TABLE `t20` (
  `id` int(11) DEFAULT NULL,
  `firstname` varchar(15) DEFAULT NULL,
  `lastname` varchar(15) DEFAULT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

-- 2ci usul

mysql> select constraint_name, constraint_type from information_schema.table_constraints where table_schema='join_test' and table_name='t20';
+-----------------+-----------------+
| constraint_name | constraint_type |
+-----------------+-----------------+
| id              | UNIQUE          |
+-----------------+-----------------+
1 row in set (0.00 sec)

Və təbii ki yenə Oracle-da olduğu kimi özümüz constraint name verə bilərik.

-- MySQL

 
create table t20(
id int,
firstname varchar(15),
lastname varchar(15),
constraint id_unikal unique key(id)
);


-- metadata

mysql> select constraint_name, constraint_type from information_schema.table_constraints where table_schema='join_test' and table_name='t20';
+-----------------+-----------------+
| constraint_name | constraint_type |
+-----------------+-----------------+
| id_unikal       | UNIQUE          |
+-----------------+-----------------+
1 row in set (0.00 sec)

Düşünürəm ki, UNİQUE constraint haqqında bu qədər kifayətdir davam edirik.

CHECK

-- Oracle

-- Syntax 1

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
check (id in(1,2,3,4))
);

>>>
table T20 created.

-- insert edek

insert into t20(id,firstname,lastname) values(5,'shahriyar','rzayev');

>>>
insert into t20(id,firstname,lastname) values(5,'shahriyar','rzayev')
Error report -
SQL Error: ORA-02290: check constraint (HR.SYS_C0011140) violated
02290. 00000 -  "check constraint (%s.%s) violated"
*Cause:    The values being inserted do not satisfy the named check
           
*Action:   do not insert values that violate the constraint.

-- Syntax 2

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
constraint id_check check (id in(1,2,3,4))
);
>>>
table T20 created.

2 Syntax dəstəklənir. Bundan əlavə gördüyümüz kimi, id CHECK constraint-ə uyğun olaraq yalnız 1, 2, 3, 4 daxil etməyə icazə verir biz 5 insert etməyə çalışdığımız üçün error çıxır. Çox gözəl.

Constraint siyahısına baxaq:

-- Oracle

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
ID_CHECK	C

CHECK-dan danışdığımız üçün NOT NULL-U qeyd etməliyik. Faktiki olaraq Oracle-da NOT NULL elə CHECK constraintdir.

-- Oracle

-- firstname-e not null verek

create table t20(
id number,
firstname varchar2(15) not null,
lastname varchar2(15),
constraint id_check check (id in(1,2,3,4))
);

-- constraint siyahısına baxaq

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
SYS_C0011142	C
ID_CHECK	C

Bizim nümunədə SYS_C0011142 = NOT NULL-un necə deyərlər adıdır və Diqqət yetirsək görərik ki,
her iki constraint-in type-ı C-dir yəni CHECK.
Çox kədərli hal kimi onu qeyd etməliyik ki, MySQL-də CHECK constraint dəstəklənmir dolayısı ilə nəzərə alsaq ki, NOT NULL = CHECK o zaman burdan belə bir nəticə çıxartmaq olar ki, NOT NULL MySQL-də ayrıca constraint kimi götürülmür gəlin test edək.

-- MySQL

create table t20(
id int,
firstname varchar(15) not null,
lastname varchar(15),
constraint id_check check (id in(1,2,3,4))
);

Cədvəl definition-nunda not null və check olmağına baxmayaraq MySQL üçün bunlar constraint hesab olunmur.
Datadictionary-dən constraint list-ə baxmaq istədikdə də bunun şahidi oluruq.

mysql> select constraint_name, constraint_type from information_schema.table_constraints where table_schema='join_test' and table_name='t20';
Empty set (0.00 sec)

Dokumentasiyada da bu açıq şəkildə qeyd olunub:

The CHECK clause is parsed but ignored by all storage engines.

Çox təəssüf.

PRİMARY KEY:

-- Oracle

-- Syntax 1

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
primary key(id)
);

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
SYS_C0011147	P


-- Syntax 2

create table t20(
id number,
firstname varchar2(15),
lastname varchar2(15),
constraint pk_id primary key(id)
);

select 
constraint_name,
constraint_type
from USER_CONSTRAINTS where table_name='T20';

>>>
PK_ID	P

Ümumi olaraq Burdan aşağıdakı nəticə çıxır:
Oracle-da PK yaradarkən ayrıca olaraq NOT NULL qeyd etməyə ehtiyac yoxdur.
Suggested by Adigozalov Qurban:
From Oracle DOC:
A primary key constraint combines a NOT NULL constraint and a unique constraint in a single declaration. That is, it prohibits multiple rows from having the same value in the same column or combination of columns and prohibits values from being null.

Həmçinin yuxarıdakı nümunədə də göstərildiyi kimi, PK-ya name verə bilirik.
indi isə eyni testləri MySQL-də edək:

-- MySQL

-- Syntax 1

create table t20(
id int,
firstname varchar(15) not null,
lastname varchar(15),
primary key(id)
);

-- Metadata

mysql> select constraint_name, constraint_type from information_schema.table_constraints where table_schema='join_test' and table_name='t20';
+-----------------+-----------------+
| constraint_name | constraint_type |
+-----------------+-----------------+
| PRIMARY         | PRIMARY KEY     |
+-----------------+-----

-- Syntax 2

create table t20(
id int,
firstname varchar(15) not null,
lastname varchar(15),
constraint pk_id primary key(id)
);

-- Metadata

mysql> select constraint_name, constraint_type from information_schema.table_constraints where table_schema='join_test' and table_name='t20';
+-----------------+-----------------+
| constraint_name | constraint_type |
+-----------------+-----------------+
| PRIMARY         | PRIMARY KEY     |
+-----------------+-----------------+
1 row in set (0.00 sec)

Yuxarıdan belə nəticə çıxarırıq ki, MySQL-də Primay Key constraint-in adını dəyişmək olmur.

From Documentation:
The name of a PRIMARY KEY is always PRIMARY, which thus cannot be used as the name for any other kind of index.

Foreign Key-lə bağlı əlavə yazı olacaq.

Təşəkkürlər 😉

Altering Table Definitions after Creation Oracle vs. MySQL

Bu yazıda sizlərlə ALTER statement-lərə baxacıq.
1 nümunə Oracle-dan daha sonra da 1 nümunə MySQL-dən.

Mövcud cədvəlimiz hər 2 DB-də eynidir.

Adding Columns:

-- Oracle

-- Syntax 1

alter table t1 add column address varchar2(25) not null;
>>>
Error starting at line : 3 in command -
alter table t1 add column address varchar2(25) not null
Error report -
SQL Error: ORA-00904: : invalid identifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:


-- Syntax 2

alter table t1 add address varchar2(25) not null;
>>>
Error starting at line : 5 in command -
alter table t1 add address varchar2(25) not null
Error report -
SQL Error: ORA-01758: table must be empty to add mandatory (NOT NULL) column
01758. 00000 -  "table must be empty to add mandatory (NOT NULL) column"
*Cause:    
*Action:

Burdan çıxan nəticə budur ki, 1ci Syntax növünü Oracle dəstəkləmir. 2-ci olaraq isə NOT NULL constraint-li column-u məlumatlar olan cədvələ daxil etmək mümkün deyil. ERROR-dan da aydın görünür:

table must be empty to add mandatory (NOT NULL) column

Eyni testler MySQL-də:

-- MySQL

-- Syntax 1

mysql> alter table t1 add column address varchar(25) not null;
Query OK, 3 rows affected (0.45 sec)
Records: 3  Duplicates: 0  Warnings: 0

-- Syntax 2

mysql> alter table t1 add address2 varchar(25) not null;
Query OK, 3 rows affected (0.28 sec)
Records: 3  Duplicates: 0  Warnings: 0

Gördüyümüz kimi hər 2 syntax tipi dəstəklənir və hətta boş olmayan cədvələ not null column əlavə edə bilirik. Möcüzəli şəkildə NOT NULL olan column-a 0 uzunluqlu boş məlumat daxil edilib:

mysql> select char_length(address),char_length(address2) from t1;
+----------------------+-----------------------+
| char_length(address) | char_length(address2) |
+----------------------+-----------------------+
|                    0 |                     0 |
|                    0 |                     0 |
|                    0 |                     0 |
+----------------------+-----------------------+
3 rows in set (0.00 sec)

Ən sonda onu qeyd edək ki, Oracle düzgün syntax zamanı column əlavə etdikdə , həmin column dataları NULL olur:

-- Oracle

select nvl(address,'null məlumat') from t1;
>>>
null məlumat
null məlumat
null məlumat

Dropping Columns:

-- Oracle

alter table t1 drop column address;

-- MySQL

alter table t1 drop column address;

Eyni syntax eyni funksionallıq.

Renaming Columns:

-- Oracle

alter table t1 rename column address to address2;
>>>
table T1 altered.

desc t1;
>>>
Name     Null Type         
-------- ---- ------------ 
ID1           NUMBER       
NAME1         VARCHAR2(25) 
NAME_ID       NUMBER       
ADDRESS2      VARCHAR2(25) 

Rename olunan zaman column definition olduğu kimi qalır.
MySQL-də rename syntax yoxdur onun əvəzinə change var:

-- MySQL

alter table t1 change address address2 varchar(25) not null;

Marking Columns as unused

-- Oracle

alter table t1 set unused column address2;

desc t1;

Name    Null Type         
------- ---- ------------ 
ID1          NUMBER       
NAME1        VARCHAR2(25) 
NAME_ID      NUMBER

Həqiqətən də unused etdi. Hətta describe-da belə görsənmədi bu column.

MySQL-də belə bir syntax yoxdur.

Making table as read-only:


-- Oracle

alter table t1 read only;

MySQL-də belə bir syntax yoxdur. Onun əvəzinə USER-ə yalnızca SELECT grant verməklə cədvəli privilege vasitəsilə read only edə bilərsiniz.

Modifying columns:
Daha bir maraqlı halı göstərək. Oracle-da boş olmayan column uzunluğunu azaltmaq istədikdə ERROR verərək bunun qarşısını alır.

Deyək ki bizim cədvəlimiz aşağıdakı kimidir:

-- Oracle

desc t1;

Name    Null Type         
------- ---- ------------ 
ID1          NUMBER       
NAME1        VARCHAR2(30) 
NAME_ID      NUMBER 

Və NUMBER tipin uzunluğunu azaltmağa çalışaq:

-- Oracle

alter table t1 modify id1 number(4,0);
>>>
Error starting at line : 3 in command -
alter table t1 modify id1 number(4,0)
Error report -
SQL Error: ORA-01440: column to be modified must be empty to decrease precision or scale
01440. 00000 -  "column to be modified must be empty to decrease precision or scale"
*Cause:    
*Action:

Eyni halı MySQL-də test edək.

-- MySQL

mysql> desc t1;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name    | varchar(25)      | YES  |     | NULL    |                |
| name_id | int(11)          | YES  |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> alter table t1 modify id tinyint not null auto_increment;
Query OK, 3 rows affected (1.23 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> desc t1;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | tinyint(4)  | NO   | PRI | NULL    | auto_increment |
| name    | varchar(10) | YES  |     | NULL    |                |
| name_id | int(11)     | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

Query OK..MySQL-də Heç bir error çıxmadı dolayısı ilə Bu anda çox diqqətli olmaq lazımdır mövcud halda, data səssizcə truncate oluna bilər.
Lakin maraqlı hal bundan ibarətdir ki, Oracle varchar tipində error çıxartmır MySQL kimi.

-- Oracle
-- 1
alter table t1 modify name1 varchar2(25);

desc t1;
>>>
Name    Null Type         
------- ---- ------------ 
ID1          NUMBER       
NAME1        VARCHAR2(25) 
NAME_ID      NUMBER    

-- 2

alter table t1 modify name1 varchar2(15);

desc t1;
>>>
Name    Null Type         
------- ---- ------------ 
ID1          NUMBER       
NAME1        VARCHAR2(15) 
NAME_ID      NUMBER  

Indi isə mövcud data uzunluğundan daha aşağı bir uzunluq ilə cədvəlimizi alter etməyə çalışaq:

-- Oracle

select length(name1) from t1;
>>>
9
5
5

-- 9-dan kiçik qiymət ilə alter

alter table t1 modify name1 varchar2(7);
>>>

alter table t1 modify name1 varchar2(7)
Error report -
SQL Error: ORA-01441: cannot decrease column length because some value is too big
01441. 00000 -  "cannot decrease column length because some value is too big"
*Cause:    
*Action:

Oracle çox gözəl şəkildə hər hansı data-nın itirilməsinin qarşısını alır.
Eyni testi MySQL-də edək.

-- MySQL

mysql> select * from t1;
+----+-----------+---------+
| id | name      | name_id |
+----+-----------+---------+
|  1 | shahriyar |       1 |
|  2 | orxan     |       2 |
|  3 | elvin     |       3 |
+----+-----------+---------+
3 rows in set (0.00 sec)


mysql> alter table t1 modify name varchar(7);
Query OK, 3 rows affected, 1 warning (1.22 sec)
Records: 3  Duplicates: 0  Warnings: 1

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

mysql> select * from t1;
+----+---------+---------+
| id | name    | name_id |
+----+---------+---------+
|  1 | shahriy |       1 |
|  2 | orxan   |       2 |
|  3 | elvin   |       3 |
+----+---------+---------+
3 rows in set (0.00 sec)

Çox təəssüf ki data-mız itirildi. Default MySQL installation işlədikdə bu kimi hallara diqqət yetirmək lazımdır.
Yuxarıdakı halın qarşısını almaq üçün my.cnf faylında sql_mode-u təyin etmək lazımdır. Ya da ki, session olaraq dəyişə bilərsiz.

mysql> set @@sql_mode='TRADITIONAL';
Query OK, 0 rows affected (0.00 sec)

mysql> alter table t1 modify name varchar(7);
ERROR 1265 (01000): Data truncated for column 'name' at row 1

Ümumiyyətlə MySQL-i install etdikdən sonra onu strict mode-a keçirmək məsləhətdir.

Təşəkkürlər 😉

Kateqoriyalar: MySQL, Oracle, Oracle SQL

Create table using Subqueries Oracle vs. MySQL

*Oracle 11g R2 , MySQL 5.5.34*

Hazır cədvəl üzərindən onunla eyni cədvəli yaratmaq məqsədilə istifadə olunan bu üsul 2 RDBMS arasında fərqliliklər görsənir.

-- MySQL

-- Numune cedvel

create table sub_test(
id int not null auto_increment,
firstname varchar(25) not null,
primary key(id),
unique(firstname)
);

-- Syntax 1

create table sub_test2 as select * from sub_test;

-- Syntax 2

create table sub_test3 select * from sub_test;

2 Syntax-ın 2-si də doğrudur.
Bir qayda olaraq subquery ilə subquery ilə yaradılan cədvəllərdə PK, FK , Unique constraints-lər yer almırlar.
Sübut:

-- MySQL

CREATE TABLE `sub_test2` (
  `id` int(11) NOT NULL DEFAULT '0',
  `firstname` varchar(25) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `sub_test3` (
  `id` int(11) NOT NULL DEFAULT '0',
  `firstname` varchar(25) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

İndi isə eyni testi Oracle-da edək:

-- Oracle

create table sub_test(
id numeric not null,
firstname varchar2(25) not null,
constraint pk_id primary key(id),
constraint un_id unique(firstname)
);

>>>
table SUB_TEST created.

-- Syntax 1
create table sub_test2 as select * from sub_test;
>>>
table SUB_TEST2 created.

-- Syntax 2
create table sub_test3 select * from sub_test;
>>>
Error starting at line : 18 in command -
create table sub_test3 select * from sub_test
Error at Command Line : 18 Column : 24
Error report -
SQL Error: ORA-00922: missing or invalid option
00922. 00000 -  "missing or invalid option"
*Cause:    
*Action:

Çox gözəl. Oracle yalnız CTAS dəstəkləyir.
Və daha əvvəl də dediyimiz kimi subquery-li create zamanı yuxarıda dediyim constraint-lər yaranmır. Oracle üçün sübut:

-- Oracle

-- sub_test cedveli

select constraint_name from user_cons_columns where table_name = 'SUB_TEST';
>>>

SYS_C0011578 -- not null
SYS_C0011579 -- not null
PK_ID        -- Primary Key   
UN_ID        -- Unique Key

-- sub_test2 cedveli

select constraint_name from user_cons_columns where table_name = 'SUB_TEST2';
>>>
SYS_C0011582 -- not null
SYS_C0011583 -- not null

Lakin belə bir hal ola bilər ki, bizə lazım olsun ki cədvəli digər cədvələ əsasən yaradaq və bütün constraintlər də həmin ikinci cədvəldə olsun.

Oracle-da bu funksiya yoxdur. Düşünürəm ki, bu Constraint və İndex yanaşmasının fərqliliyindəndir. Ya da ki ekspertlər izah etsin ))

-- MySQL

create table sub_test4 like sub_test;

>>>

CREATE TABLE `sub_test4` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `firstname` varchar(25) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `firstname` (`firstname`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Düşünürəm ki, mövzunu izah etdik.

Təşəkkürlər ))

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

Noyabr 6, 2013 2 şərh

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 😉