UPDATE dan DELETE

Pembaruan dan penghapusan yang aman, termasuk pola UPDATE berbasis JOIN.

Daftar isi

UPDATE dan DELETE mengubah serta menghapus data yang sudah tersimpan, dan keduanya merupakan pernyataan dengan risiko terbesar apabila klausa WHERE-nya salah atau lupa ditulis. Topik ini membahas pembaruan tunggal dan pembaruan dengan ekspresi, pembaruan multi-tabel berbasis JOIN, penghapusan baris terpilih, serta perbedaan DELETE dengan TRUNCATE TABLE. Setelah membacanya, perubahan data pada tabel apa pun dapat dilakukan disertai pagar keselamatan yang jelas.

Contoh sepanjang topik ini memakai basis data sirkulasi berisi tabel buku dan peminjaman. Tabel peminjaman menyimpan catatan pinjam meminjam dengan kolom tanggal_kembali yang bernilai NULL selama buku masih dipinjam. Skema berikut membuat ulang basis data tersebut dari nol beserta isinya, sehingga setiap contoh menghasilkan keadaan awal yang sama persis.

sql skema-sirkulasi.sql
-- tidak-dijalankan
DROP DATABASE IF EXISTS sirkulasi;
CREATE DATABASE sirkulasi;
USE sirkulasi;

CREATE TABLE buku (
  id    INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  judul VARCHAR(120) NOT NULL,
  stok  TINYINT UNSIGNED NOT NULL DEFAULT 0
);

CREATE TABLE peminjaman (
  id              INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  buku_id         INT UNSIGNED NOT NULL,
  tanggal_pinjam  DATE NOT NULL,
  tanggal_kembali DATE NULL
);

INSERT INTO buku (judul, stok) VALUES
  ('Dasar Basis Data Relasional', 5),
  ('Pemrograman SQL untuk Pemula', 3),
  ('Struktur Data dan Algoritma', 8),
  ('Jaringan Komputer Dasar', 4);

INSERT INTO peminjaman (buku_id, tanggal_pinjam, tanggal_kembali) VALUES
  (1, '2026-10-20', '2026-10-27'),
  (1, '2026-10-22', NULL),
  (2, '2026-10-24', NULL),
  (3, '2026-10-25', NULL);
bash
# membuat ulang basis data sirkulasi beserta tabel dan isinya
mysql -u root < skema-sirkulasi.sql

Memperbarui baris dengan UPDATE#

UPDATE mengubah nilai kolom pada baris yang memenuhi kondisi tertentu. Struktur dasarnya menyebut nama tabel, daftar penugasan kolom pada klausa SET, dan klausa WHERE yang memilih baris sasarannya. Nilai yang ditugaskan boleh berupa konstanta maupun ekspresi yang membaca nilai lama kolom itu sendiri, misalnya stok = stok - 1 untuk mengurangi stok satu buku karena sedang dipinjam.

bash
# mengurangi stok satu buku karena sedang dipinjam
mysql -t -u root sirkulasi <<'SQL'
UPDATE buku SET stok = stok - 1 WHERE id = 1;

SELECT id, judul, stok FROM buku ORDER BY id;
SQL
text Keluaran
+----+------------------------------+------+
| id | judul                        | stok |
+----+------------------------------+------+
|  1 | Dasar Basis Data Relasional  |    4 |
|  2 | Pemrograman SQL untuk Pemula |    3 |
|  3 | Struktur Data dan Algoritma  |    8 |
|  4 | Jaringan Komputer Dasar      |    4 |
+----+------------------------------+------+

Klausa WHERE id = 1 membatasi pembaruan pada satu baris, dan keluaran SELECT membuktikan hanya stok buku pertama yang berubah. Karena sisi kanan penugasan dibaca sebelum nilai baru ditulis, ekspresi aritmetika pada UPDATE aman dipakai untuk penyesuaian relatif. Pernyataan berikut menambah stok dua judul sekaligus hasil pengadaan baru, dan klausa WHERE id IN (2, 3) membatasi cakupannya.

bash
# menambah stok dua judul hasil pengadaan baru
mysql -t -u root sirkulasi <<'SQL'
UPDATE buku SET stok = stok + 10 WHERE id IN (2, 3);

SELECT id, judul, stok FROM buku ORDER BY id;
SQL
text Keluaran
+----+------------------------------+------+
| id | judul                        | stok |
+----+------------------------------+------+
|  1 | Dasar Basis Data Relasional  |    4 |
|  2 | Pemrograman SQL untuk Pemula |   13 |
|  3 | Struktur Data dan Algoritma  |   18 |
|  4 | Jaringan Komputer Dasar      |    4 |
+----+------------------------------+------+

WHERE sebagai pagar keselamatan#

Pernyataan UPDATE tanpa klausa WHERE memperbarui setiap baris pada tabel. Perilaku itu sesuai definisi SQL, tetapi menjadi sumber kehilangan data terbesar apabila ditulis tanpa sengaja. Klien mysql menyediakan opsi --safe-updates yang menolak UPDATE dan DELETE tanpa WHERE yang memakai kolom kunci, sehingga kecerobohan semacam itu berhenti sebagai error dan tidak berlanjut menjadi bencana.

bash
# UPDATE tanpa WHERE ditolak pada klien dengan --safe-updates
mysql -u root --safe-updates sirkulasi -e "UPDATE buku SET stok = 0;"
text Keluaran
ERROR 1175 (HY000) at line 1: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

Pesan errornya menyebut syarat yang dilanggar, yaitu klausa WHERE yang memakai kolom kunci. Secara lengkap, opsi ini menerima pernyataan yang WHERE-nya memakai kolom kunci atau yang disertai batasan LIMIT. Data pada tabel tidak tersentuh sedikit pun karena pernyataan ditolak sebelum dieksekusi.

UPDATE berbasis JOIN#

Banyak pembaruan nyata bergantung pada data tabel lain. MySQL mendukung bentuk UPDATE multi-tabel yang menggabungkan tabel sasaran dengan tabel lain melalui JOIN, lalu menetapkan nilai kolom pada tabel mana pun yang terlibat. Contoh paling wajar adalah pencatatan pengembalian: baris peminjaman diberi tanggal kembali, dan sekaligus stok bukunya ditambah satu.

bash
# mencatat pengembalian sekaligus menambah stok bukunya
mysql -t -u root sirkulasi <<'SQL'
UPDATE peminjaman p
JOIN buku b ON b.id = p.buku_id
SET p.tanggal_kembali = '2026-11-05',
    b.stok = b.stok + 1
WHERE p.id = 3;

SELECT p.id, b.judul, p.tanggal_pinjam, p.tanggal_kembali, b.stok
FROM peminjaman p
JOIN buku b ON b.id = p.buku_id
ORDER BY p.id;
SQL
text Keluaran
+----+------------------------------+----------------+-----------------+------+
| id | judul                        | tanggal_pinjam | tanggal_kembali | stok |
+----+------------------------------+----------------+-----------------+------+
|  1 | Dasar Basis Data Relasional  | 2026-10-20     | 2026-10-27      |    4 |
|  2 | Dasar Basis Data Relasional  | 2026-10-22     | NULL            |    4 |
|  3 | Pemrograman SQL untuk Pemula | 2026-10-24     | 2026-11-05      |   14 |
|  4 | Struktur Data dan Algoritma  | 2026-10-25     | NULL            |   18 |
+----+------------------------------+----------------+-----------------+------+

Alias p dan b membedakan kedua tabel, sedangkan WHERE p.id = 3 memilih tepat satu baris peminjaman. Tanpa klausa WHERE, setiap pasangan baris pada hasil join ikut diperbarui, sehingga disiplin WHERE dari bagian sebelumnya tetap berlaku pada bentuk multi-tabel. Bentuk ini juga menggantikan dua pernyataan terpisah dengan satu pernyataan yang konsisten, karena kedua perubahan terjadi bersamaan.

Menghapus baris dengan DELETE#

DELETE menghapus baris yang memenuhi kondisi klausa WHERE, dan tanpa klausa itu seluruh baris pada tabel terhapus. Strukturnya lebih sederhana daripada UPDATE karena tidak ada daftar kolom, tetapi akibatnya permanen pada sesi tanpa transaksi. Pernyataan berikut menghapus satu catatan peminjaman yang sudah selesai, lalu isi tabel diperiksa untuk membuktikan barisnya hilang.

bash
# menghapus satu catatan peminjaman yang sudah dikembalikan
mysql -u root sirkulasi -e "DELETE FROM peminjaman WHERE id = 1;"

# memastikan barisnya hilang
mysql -t -u root sirkulasi -e "SELECT id, buku_id, tanggal_kembali FROM peminjaman ORDER BY id;"
text Keluaran
+----+---------+-----------------+
| id | buku_id | tanggal_kembali |
+----+---------+-----------------+
|  2 |       1 | NULL            |
|  3 |       2 | 2026-11-05      |
|  4 |       3 | NULL            |
+----+---------+-----------------+

Baris yang terhapus tidak mengembalikan penghitung AUTO_INCREMENT. Pernyataan berikut menghapus seluruh baris peminjaman dengan DELETE tanpa WHERE, lalu menyisipkan satu baris baru untuk memperlihatkan bahwa penomoran berlanjut dari nilai terakhir, bukan dari awal.

bash
# menghapus seluruh baris, lalu menyisipkan satu baris baru
mysql -t -u root sirkulasi <<'SQL'
DELETE FROM peminjaman;

INSERT INTO peminjaman (buku_id, tanggal_pinjam) VALUES (4, '2026-11-06');
SELECT id, buku_id, tanggal_pinjam FROM peminjaman;
SQL
text Keluaran
+----+---------+----------------+
| id | buku_id | tanggal_pinjam |
+----+---------+----------------+
|  5 |       4 | 2026-11-06     |
+----+---------+----------------+

TRUNCATE TABLE mengosongkan tabel dengan cepat sekaligus mengembalikan penghitung AUTO_INCREMENT ke titik awal. Pernyataan ini tidak menerima klausa WHERE, sehingga hanya cocok untuk pengosongan penuh yang memang dimaksudkan.

bash
# TRUNCATE mengosongkan tabel sekaligus mengembalikan penghitung
mysql -t -u root sirkulasi <<'SQL'
TRUNCATE TABLE peminjaman;

INSERT INTO peminjaman (buku_id, tanggal_pinjam) VALUES (4, '2026-11-06');
SELECT id, buku_id, tanggal_pinjam FROM peminjaman;
SQL
text Keluaran
+----+---------+----------------+
| id | buku_id | tanggal_pinjam |
+----+---------+----------------+
|  1 |       4 | 2026-11-06     |
+----+---------+----------------+

Kesalahan umum#

Kesalahan pertama adalah menulis UPDATE atau DELETE tanpa klausa WHERE saat maksudnya hanya menyasar sebagian baris. Semua baris pada tabel ikut terdampak sebelum kesalahan itu disadari. Cegah dengan menjalankan SELECT dengan klausa WHERE yang sama terlebih dahulu dan mengaktifkan --safe-updates pada sesi kerja.

Kesalahan kedua adalah memakai TRUNCATE TABLE untuk penghapusan bersyarat. TRUNCATE tidak menerima WHERE dan mengosongkan seluruh tabel, jadi baris yang seharusnya dipertahankan ikut hilang. Gunakan DELETE dengan WHERE untuk penghapusan terpilih, dan gunakan TRUNCATE hanya untuk pengosongan penuh.

Kesalahan ketiga adalah menghapus baris induk yang masih dirujuk oleh foreign key. MySQL menolaknya dengan error 1451 agar rujukan tidak menggantung. Tangani dengan menghapus atau melepas baris anak terlebih dahulu, atau rancang aksi ON DELETE yang sesuai pada constraint-nya sejak awal.

Ringkasan#

  • UPDATE dan DELETE selalu menyertakan WHERE, dan ekspresi pada SET dibaca dari nilai lama sebelum nilai baru ditulis.
  • UPDATE multi-tabel dengan JOIN memperbarui kolom pada beberapa tabel sekaligus dalam satu pernyataan.
  • DELETE tanpa WHERE menghapus seluruh baris, sedangkan penghitung AUTO_INCREMENT tetap berlanjut dari nilai terakhir.
  • TRUNCATE TABLE mengosongkan tabel penuh dan mengembalikan penghitung, tetapi tidak menerima WHERE.

Referensi#