Angka bulat adalah data yang paling sering kita simpan: jumlah stok, nomor telepon, harga dalam rupiah utuh, hingga penghitung kunjungan. MySQL menyediakan lima ukuran tipe integer yang berbeda supaya kita tidak memakai gudang raksasa untuk menyimpan satu kotak korek api. Pada Chapter ini kita akan memetakan kelima ukuran tersebut, mencoba menyimpan nilai yang melebihi batasnya, membongkar mitos INT(11) yang masih beredar di banyak tutorial lama, dan mengenal atribut UNSIGNED untuk kolom yang tidak pernah bernilai negatif.

Lima Ukuran INTEGER #

Kelima tipe integer dibedakan oleh jumlah byte penyimpanan — dan jumlah byte tersebut menentukan rentang nilai yang bisa ditampung. Semakin besar byte, semakin luas rentangnya, dan semakin banyak ruang yang dipakai per baris. Tabel berikut merangkum rentang lengkap versi MySQL 8.4:

TipeByteRentang SIGNEDRentang UNSIGNED
TINYINT1-128 s.d. 1270 s.d. 255
SMALLINT2-32.768 s.d. 32.7670 s.d. 65.535
MEDIUMINT3-8.388.608 s.d. 8.388.6070 s.d. 16.777.215
INT4-2.147.483.648 s.d. 2.147.483.6470 s.d. 4.294.967.295
BIGINT8sekitar -9,22 × 10¹⁸ s.d. 9,22 × 10¹⁸0 s.d. 18.446.744.073.709.551.615

Aturan praktisnya sederhana: pilih tipe terkecil yang masih menampung nilai terbesar yang masuk akal untuk kolom tersebut. Kolom stok_rak TINYINT cukup untuk rak yang maksimal memuat ratusan barang, sedangkan kolom harga properti atau jumlah populasi dunia sudah layak memakai BIGINT. Kesalahan klasik pemula adalah memakai INT untuk semua kolom angka — sah-sah saja, tetapi tabel berjuta-juta baris akan membayar mahal ruang dan memori ekstra yang sebenarnya tidak diperlukan.

Membuat Tabel Latihan #

Kita mulai dengan menyiapkan database latihan khusus section ini, lalu membuat tabel barang yang memakai lima ukuran integer sekaligus:

sql
DROP DATABASE IF EXISTS belajar_tipe;
CREATE DATABASE belajar_tipe;
USE belajar_tipe;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed

Baris pertama berasal dari DROP DATABASE IF EXISTS yang tidak menemukan database lama — perintah diabaikan dengan aman dan hanya mencatat satu warning informatif. CREATE DATABASE kemudian membuat belajar_tipe baru, dan USE mengaktifkannya untuk sesi kita (ditandai respons Database changed). Pola tiga baris ini akan kita ulang di setiap chapter section Tipe Data supaya latihan selalu dimulai dari keadaan bersih.

sql
CREATE TABLE barang (
  id SMALLINT UNSIGNED,
  nama VARCHAR(50),
  stok_rak TINYINT UNSIGNED,
  stok_gudang MEDIUMINT UNSIGNED,
  harga_satuan INT UNSIGNED,
  total_nilai BIGINT UNSIGNED
);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Mari kita bedah definisi tabel di atas baris per baris:

  1. Baris 1 (CREATE TABLE barang (): Membuat tabel baru bernama barang; tanda kurung buka mengawali daftar enam definisi kolom.
  2. Baris 2 (id SMALLINT UNSIGNED): Kolom identitas barang memakai SMALLINT UNSIGNED — maksimal 65.535 nomor barang, cukup untuk toko latihan kita.
  3. Baris 3 (nama VARCHAR(50)): Nama barang bertipe string variabel; tipe string akan dibedah tuntas pada chapter STRING.
  4. Baris 4 (stok_rak TINYINT UNSIGNED): Stok di rak memakai tipe terkecil — maksimal 255 unit per barang.
  5. Baris 5 (stok_gudang MEDIUMINT UNSIGNED): Stok gudang bisa jutaan unit sehingga naik satu kelas ke MEDIUMINT.
  6. Baris 6 (harga_satuan INT UNSIGNED): Harga satuan dalam rupiah utuh memakai INT UNSIGNED hingga 4,29 miliar.
  7. Baris 7 (total_nilai BIGINT UNSIGNED): Total nilai persediaan (harga × jumlah) bisa melampaui 4,29 miliar, maka dipakai BIGINT.

Sekarang kita isi tiga baris data dan membacanya kembali:

sql
INSERT INTO barang (id, nama, stok_rak, stok_gudang, harga_satuan, total_nilai)
VALUES
  (1, 'Pensil Kayu', 12, 500, 2500, 1280000),
  (2, 'Buku Tulis 38', 8, 1200, 4500, 5400000),
  (3, 'Penghapus', 25, 3000, 1500, 4500000);

SELECT id, nama, stok_rak, stok_gudang, harga_satuan, total_nilai
FROM barang
ORDER BY id;

Output yang Dihasilkan:

text
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

+------+---------------+----------+-------------+--------------+-------------+
| id   | nama          | stok_rak | stok_gudang | harga_satuan | total_nilai |
+------+---------------+----------+-------------+--------------+-------------+
|    1 | Pensil Kayu   |       12 |         500 |         2500 |     1280000 |
|    2 | Buku Tulis 38 |        8 |        1200 |         4500 |     5400000 |
|    3 | Penghapus     |       25 |        3000 |         1500 |     4500000 |
+------+---------------+----------+-------------+--------------+-------------+
3 rows in set (0.00 sec)

Tiga baris tersimpan dan ditampilkan kembali persis seperti nilainya — angka bulat tidak mengalami pembulatan maupun konversi bentuk. Klausa ORDER BY id kita pakai supaya urutan tampilan selalu sama meskipun MySQL kelak menyimpan barisnya dengan urutan fisik yang berbeda.

Batas Rentang dan Strict Mode #

Apa yang terjadi jika kita memaksa menyimpan nilai di luar rentang? Mari kita coba memasukkan stok rak sebesar 300 ke kolom TINYINT UNSIGNED yang batas maksimalnya 255:

sql
-- @error
INSERT INTO barang (id, nama, stok_rak) VALUES (4, 'Rautan', 300);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

ERROR 1264 (22003): Out of range value for column 'stok_rak' at row 1
Bye

Server menolak statement tersebut dengan galat Out of range value for column 'stok_rak' at row 1 dan seluruh baris tidak tersimpan — angka 300 tidak dipangkas menjadi 255 secara diam-diam. Perlakuan ini berasal dari strict mode (STRICT_TRANS_TABLES) yang aktif secara bawaan di MySQL 8.4: nilai yang tidak muat dianggap kesalahan data, bukan sesuatu yang boleh ditebak server. Pada mode longgar yang dipakai versi-versi lama, MySQL justru memangkas nilai ke batas terdekat dan hanya mengeluarkan peringatan — perilaku yang sering menyembunyikan bug aplikasi. Karena strict mode adalah standar modern, kita menulis kode dengan asumsi out-of-range selalu gagal keras.

INT(11) dan Display Width yang Usang #

Banyak tutorial lama menulis INT(11) atau TINYINT(4) seolah angka di dalam kurung membatasi jumlah digit. Itu adalah display width — lebar tampilan untuk alat klien lawas — dan sama sekali tidak membatasi rentang nilai: kolom INT(11) tetap bisa menyimpan 2 miliar. MySQL sudah menandai fitur ini deprecated sejak versi 8.0.17, dan di MySQL 8.4 lebar tampilan diabaikan serta dihilangkan dari metadata tabel. Kita bisa membuktikannya langsung:

sql
CREATE TABLE lebar_usang (nomor INT(11), kode TINYINT(4));
SHOW WARNINGS;
DESC lebar_usang;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 2 warnings (0.00 sec)

+---------+------+------------------------------------------------------------------------------+
| Level   | Code | Message                                                                      |
+---------+------+------------------------------------------------------------------------------+
| Warning | 1681 | Integer display width is deprecated and will be removed in a future release. |
| Warning | 1681 | Integer display width is deprecated and will be removed in a future release. |
+---------+------+------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| nomor | int     | YES  |     | NULL    |       |
| kode  | tinyint | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Kita mendeklarasikan INT(11) dan TINYINT(4), dan hasilnya membuktikan dua hal sekaligus: kolom Type pada DESC hanya menampilkan int dan tinyint, serta SHOW WARNINGS mencatat peringatan bahwa lebar tampilan integer sudah usang. MySQL 8.4 membuang angka lebar tampilan begitu tabel dibuat dan menandai penulisannya sebagai praktik terlarang di masa depan. Kesimpulan praktisnya: tulis INT, bukan INT(11); angka di kurung itu tidak punya efek apa pun pada data yang disimpan. Satu-satunya pengecualian sejarah adalah TINYINT(1) yang lazim dipakai sebagai konvensi kolom boolean — hal itu kita bahas pada chapter BOOLEAN dan Nilai Logika.

INT UNSIGNED untuk Nilai Non-Negatif #

Atribut UNSIGNED membuang sisi negatif dari rentang dan melipatgandakan batas atasnya. Tabel barang kita sejak awal memakai UNSIGNED pada semua kolom angka karena stok, harga, dan penghitung tidak pernah bernilai negatif. Untuk melihat seberapa jauh batasnya naik, kita simpan nilai maksimal INT UNSIGNED pada tabel penghitung kunjungan:

sql
CREATE TABLE pengunjung (hari DATE, jumlah INT UNSIGNED);
INSERT INTO pengunjung VALUES ('2026-01-15', 4294967295);
SELECT hari, jumlah, jumlah + 1 AS batas_terlampaui FROM pengunjung;

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)

+------------+------------+------------------+
| hari       | jumlah     | batas_terlampaui |
+------------+------------+------------------+
| 2026-01-15 | 4294967295 |       4294967296 |
+------------+------------+------------------+
1 row in set (0.00 sec)

Baris dengan nilai 4294967295 tersimpan tanpa masalah — angka tersebut justru menyebabkan galat Out of range bila kolomnya memakai INT biasa. Perhatikan juga kolom batas_terlampaui: ekspresi jumlah + 1 melebihi 4,29 miliar sehingga hasilnya meluas ke tipe BIGINT dan tetap dihitung. Sebaliknya, nilai negatif kini terlarang:

sql
-- @error
INSERT INTO pengunjung VALUES ('2026-01-16', -1);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

ERROR 1264 (22003): Out of range value for column 'jumlah' at row 1
Bye

Kolom INT UNSIGNED menolak -1 dengan galat out-of-range yang sama seperti kasus TINYINT kita sebelumnya. Sisi negatif rentang telah “dipindahtangankan” untuk memperluas sisi positif — pertukaran yang menguntungkan selama datanya memang tidak mungkin negatif. Konsekuensi lain dari pertukaran ini — termasuk jebakan pengurangan pada kolom UNSIGNED — akan kita bedah tuntas pada chapter SIGNED dan UNSIGNED.

Terakhir, kita bereskan database latihan sebelum pindah topik:

sql
DROP DATABASE belajar_tipe;

Output yang Dihasilkan:

text
Query OK, 3 rows affected (0.00 sec)

Referensi #

Integer menuntaskan angka bulat, tetapi harga 4.500,50 rupiah masih menyisakan pecahan yang menuntut ketelitian. Chapter berikutnya memperkenalkan DECIMAL untuk angka pecahan yang persis dan membedah mengapa FLOAT/DOUBLE bisa membuat perhitungan uang melenceng.