Tabel yang kita buat dengan CREATE TABLE pada dasarnya masih lemari kosong: strukturnya sudah ada, tetapi belum berisi satu baris data pun. Perintah INSERT adalah pintu masuk data ke dalam tabel — setiap produk, pelanggan, dan transaksi di aplikasi nyata lahir dari statement ini. Pada Chapter ini kita akan mengisi tabel produk baris demi baris, membedah bentuk lengkap INSERT ... VALUES dengan daftar kolom eksplisit, mengenal cara MySQL menerima string, angka, tanggal, dan NULL, lalu menutup dengan bentuk ringkas INSERT ... SELECT untuk menyalin data antartabel.

Menyiapkan Tabel Latihan #

Kita mulai dari keadaan bersih seperti biasa: satu database latihan khusus manipulasi data, lalu satu tabel sederhana bertoko alat tulis:

sql
CREATE DATABASE belajar_dml;
USE belajar_dml;

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE produk (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nama VARCHAR(100) NOT NULL,
  harga DECIMAL(10,2) NOT NULL,
  stok INT NOT NULL DEFAULT 0,
  tanggal_masuk DATE
);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Tabel ini punya lima kolom yang sengaja dipilih agar mewakili jenis nilai yang paling sering kita sisipkan: id diisi otomatis oleh AUTO_INCREMENT, nama menampung teks, harga menampung uang, stok punya nilai bawaan 0, dan tanggal_masuk bertipe tanggal yang boleh kosong. Kombinasi tersebut membuat kita bisa mempraktikkan seluruh variasi nilai dalam satu tabel yang sama.

INSERT dengan Daftar Kolom Eksplisit #

Bentuk paling aman dan paling sering dipakai adalah menyebutkan kolom tujuan secara eksplisit, lalu memberikan nilai dalam urutan yang sama:

sql
INSERT INTO produk (nama, harga, stok, tanggal_masuk)
VALUES ('Buku Tulis', 4500.00, 120, '2026-01-10');

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

Respons Query OK, 1 row affected menandakan tepat satu baris baru tersimpan di tabel produk. Berbeda dari CREATE TABLE yang melaporkan 0 rows affected karena hanya mengubah struktur, INSERT adalah perintah DML (Data Manipulation Language) sehingga hitungan barisnya mengacu pada data yang benar-benar berubah. Mari kita bedah setiap bagiannya:

  1. Baris 1 (INSERT INTO produk (): Keyword INSERT INTO diikuti nama tabel tujuan, lalu tanda kurung yang membuka daftar kolom. Urutan kolom dalam kurung ini bebas — tidak harus sama dengan urutan definisi di CREATE TABLE.
  2. Baris 1 lanjutan (nama, harga, stok, tanggal_masuk): Daftar kolom yang akan diisi. Kolom id sengaja tidak disebut karena AUTO_INCREMENT mengisinya sendiri.
  3. Baris 2 (VALUES (...)): Keyword VALUES membuka daftar nilai. Jumlah dan urutan nilai wajib persis mengikuti daftar kolom — nilai pertama 'Buku Tulis' masuk ke nama, nilai kedua 4500.00 masuk ke harga, dan seterusnya.

Setelah statement berhasil, kita bisa memeriksa hasilnya dengan SELECT — perintah baca data yang akan dibahas tuntas pada chapter berikutnya:

sql
SELECT * FROM produk ORDER BY id;

Output yang Dihasilkan:

text
+----+------------+---------+------+---------------+
| id | nama       | harga   | stok | tanggal_masuk |
+----+------------+---------+------+---------------+
|  1 | Buku Tulis | 4500.00 |  120 | 2026-01-10    |
+----+------------+---------+------+---------------+
1 row in set (0.00 sec)

Kolom id terisi 1 otomatis meskipun tidak kita sebutkan, dan seluruh nilai masuk ke kolom yang benar. Urutan kolom pada daftar eksplisit inilah yang menjadi jaminan kita: nilai selalu dipasangkan berdasarkan nama kolom yang kita tulis, bukan berdasarkan kebetulan urutan.

Jenis Nilai: String, Angka, Tanggal, dan NULL #

MySQL memperlakukan jenis nilai dengan aturan penulisan yang berbeda. Nilai string seperti 'Buku Tulis' dan nilai tanggal seperti '2026-01-10' wajib diapit tanda kutip tunggal, sedangkan angka seperti 4500.00 dan 120 ditulis tanpa tanda kutip. Tanggal mengikuti format YYYY-MM-DD sesuai standar ISO 8601, jadi 15 Januari 2026 tidak akan diterima. Sementara itu, NULL ditulis tanpa kutip sebagai penanda “nilai belum diketahui” — pada contoh berikut tanggal masuknya memang belum dicatat:

sql
INSERT INTO produk (nama, harga, stok, tanggal_masuk)
VALUES ('Penggaris', 5000.00, 80, NULL);

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

Kolom yang tidak kita sebutkan sama sekali memakai nilai bawaannya. Statement berikut hanya mengisi nama dan harga, sehingga stok diisi 0 dari klausa DEFAULT 0 dan tanggal_masuk menjadi NULL:

sql
INSERT INTO produk (nama, harga)
VALUES ('Kertas HVS A4', 25000.00);

SELECT * FROM produk ORDER BY id;

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

+----+---------------+----------+------+---------------+
| id | nama          | harga    | stok | tanggal_masuk |
+----+---------------+----------+------+---------------+
|  1 | Buku Tulis    |  4500.00 |  120 | 2026-01-10    |
|  2 | Penggaris     |  5000.00 |   80 | NULL          |
|  3 | Kertas HVS A4 | 25000.00 |    0 | NULL          |
+----+---------------+----------+------+---------------+
3 rows in set (0.00 sec)

Satu Statement, Dua Baris #

Statement INSERT juga menerima lebih dari satu baris nilai dalam satu kali eksekusi:

sql
INSERT INTO produk (nama, harga, stok, tanggal_masuk)
VALUES
  ('Pensil 2B', 3000.00, 200, '2026-01-11'),
  ('Penghapus', 2500.00, 150, '2026-01-12');

Output yang Dihasilkan:

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

Perhatikan dua hal pada responsnya: 2 rows affected karena dua baris tersimpan, dan baris Records: 2 Duplicates: 0 Warnings: 0 yang muncul di client interaktif sebagai ringkasan statement multi-baris. Perbandingan 1 row affected versus 2 rows affected ini penting karena angka tersebut adalah satu-satunya konfirmasi jumlah data yang masuk — bila kita mengirim lima baris tetapi responsnya menyebut 3 rows affected, ada yang tidak beres dan perlu diperiksa. Bentuk multi-baris lengkap dengan pembahasan performa dan urutan id akan kita bahas tuntas pada chapter INSERT Multiple Rows.

INSERT Tanpa Daftar Kolom #

MySQL membolehkan INSERT tanpa daftar kolom sama sekali, asalkan kita menyediakan nilai untuk SELURUH kolom dalam urutan definisi tabel:

sql
INSERT INTO produk VALUES (NULL, 'Map Plastik', 8500.00, 35, '2026-01-14');

SELECT id, nama FROM produk ORDER BY id;

Output yang Dihasilkan:

text
Query OK, 1 row affected (0.00 sec)

+----+---------------+
| id | nama          |
+----+---------------+
|  1 | Buku Tulis    |
|  2 | Penggaris     |
|  3 | Kertas HVS A4 |
|  4 | Pensil 2B     |
|  5 | Penghapus     |
|  6 | Map Plastik   |
+----+---------------+
6 rows in set (0.00 sec)

Nilai NULL pada posisi pertama membuat AUTO_INCREMENT tetap mengisi id secara otomatis, jadi statement ini berhasil. Namun bentuk ini rapuh: begitu struktur tabel berubah — misalnya kolom baru ditambahkan lewat ALTER TABLE, atau urutan kolom ditukar — statement lama langsung gagal atau lebih buruk, nilai masuk ke kolom yang salah karena jumlahnya masih kebetulan cocok.

Menyalin Data dengan INSERT … SELECT #

Bentuk terakhir yang perlu kita kenal adalah INSERT ... SELECT: alih-alih menulis nilai secara manual, sumber nilainya adalah hasil query dari tabel lain. Contoh berikut membuat tabel arsip sederhana, lalu menyalin produk yang stoknya banyak (minimal 100) ke dalamnya:

sql
CREATE TABLE produk_arsip (
  nama VARCHAR(100) NOT NULL,
  harga DECIMAL(10,2) NOT NULL
);

INSERT INTO produk_arsip (nama, harga)
SELECT nama, harga
FROM produk
WHERE stok >= 100;

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

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

Bagian SELECT nama, harga FROM produk WHERE stok >= 100 membaca baris sumber, lalu setiap baris hasilnya disisipkan ke produk_arsip — pada data kita, tiga produk memenuhi syarat tersebut sehingga responsnya melaporkan 3 rows affected. Klausa WHERE di sini baru perlu dipahami sebagai penyaring baris; seluk-beluknya akan dibahas tuntas pada Section Filtering dan Sorting. Kedalaman penuh pola INSERT ... SELECT — kolom yang harus cocok, menyalin seluruh tabel, dan kombinasinya dengan multi-baris — menyusul di chapter INSERT Multiple Rows.

Membersihkan Database Latihan #

Praktik kita selesai untuk chapter ini. Database belajar_dml beserta seluruh tabelnya bisa kita hapus agar server latihan kembali rapi:

sql
DROP DATABASE belajar_dml;

Output yang Dihasilkan:

text
Query OK, 2 rows affected (0.00 sec)

Respons 2 rows affected pada DROP DATABASE menghitung jumlah tabel yang ikut terhapus — produk dan produk_arsip. Respons ini sekaligus mengingatkan kita bahwa hitungan baris pada respons MySQL selalu punya makna spesifik: 1 row untuk satu baris data baru, N rows untuk statement multi-baris, dan jumlah tabel untuk statement yang menjatuhkan database.

Referensi #

Baris-baris data kini hidup di dalam tabel, dan keberadaannya terkonfirmasi lewat SELECT yang kita pakai sebagai alat pemeriksa berkali-kali di atas. Chapter berikutnya membalik arah perhatian kita: membaca data secara serius dengan SELECT — memilih kolom tertentu, memberi nama alias, menghitung nilai baru langsung di dalam query, hingga membatasi jumlah baris hasil.