Data yang tersimpan tidak pernah diam: harga naik, stok berkurang, produk lama pensiun dari daftar. Dua statement DML terakhir Section ini mengikuti perubahan itu — UPDATE mengubah isi baris, DELETE menghilangkannya. Keduanya tangguh dan berbahaya dengan cara yang sama: satu statement mampu mengubah atau menghapus jutaan baris sekaligus, tanpa konfirmasi, tanpa keranjang sampah. Chapter ini membedah keduanya beserta cara mengukur dan membatasi efeknya.
Sesi latihan memakai data toko yang sama dengan Chapter Memfilter Data dengan WHERE. Jika memulai dari titik ini, jalankan dulu skrip persiapan berikut:
CREATE TABLE pelanggan (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL,
kota TEXT
);
CREATE TABLE produk (
id INTEGER PRIMARY KEY,
nama TEXT NOT NULL UNIQUE,
harga INTEGER NOT NULL CHECK (harga >= 0),
stok INTEGER DEFAULT 0
);
INSERT INTO pelanggan (nama, kota) VALUES
('Budi', 'Jakarta'),
('Siti', 'Bandung'),
('Ani', 'Surabaya'),
('Joko', 'Jakarta'),
('Rina', NULL);
INSERT INTO produk (nama, harga, stok) VALUES
('Pensil', 3000, 120),
('Buku Tulis', 5500, 45),
('Penghapus', 2500, 80),
('Tas Sekolah', 85000, 12),
('Botol Air', 25000, 30),
('Rautan Pensil', 8000, NULL);
INSERT INTO produk (nama, harga) VALUES ('Papan Tulis Kecil', 15000);UPDATE dan SET #
Bentuk dasarnya: tabel, kolom beserta nilai barunya, lalu kondisi baris mana yang diubah:
sqlite> UPDATE produk SET harga = 3200 WHERE nama = 'Pensil';
sqlite> SELECT nama, harga FROM produk WHERE nama = 'Pensil';
Pensil|3200
sqlite>Bedah statement pertama:
UPDATE produk— tabel yang barisnya akan diubah.SET harga = 3200— kolomhargadiisi nilai baru untuk setiap baris yang lolos filter.WHERE nama = 'Pensil'— hanya baris bernamaPensilyang terpengaruh.
Lebih dari satu kolom bisa diubah sekaligus, dan nilai barunya boleh berupa ekspresi yang membaca kondisi baris itu sendiri — termasuk kolom yang sedang diubah:
sqlite> UPDATE produk
...> SET harga = 6000, stok = stok + 10
...> WHERE nama = 'Buku Tulis';
sqlite> SELECT nama, harga, stok FROM produk WHERE nama = 'Buku Tulis';
Buku Tulis|6000|55
sqlite>Ekspresi stok + 10 dibaca dari nilai lama (45), lalu hasilnya (55) menggantikan nilai kolom stok pada baris yang sama.
Mengukur Efek dengan changes() #
Setelah UPDATE atau DELETE selesai, fungsi changes() melaporkan berapa baris yang terpengaruh:
sqlite> UPDATE produk SET harga = 2750 WHERE nama = 'Penghapus';
sqlite> SELECT changes();
1
sqlite> UPDATE produk SET harga = 999 WHERE nama = 'Produk Fantasi';
sqlite> SELECT changes();
0
sqlite>Update kedua tidak menghasilkan error — baris bernama Produk Fantasi memang tidak ada, sehingga nol baris berubah. Pola “tidak error, nol efek” ini penting diinternalisasi: UPDATE dan DELETE tidak pernah mengeluh ketika WHERE-nya tidak menemukan apa pun. Verifikasi lewat changes() adalah satu-satunya cara memastikan statement benar-benar mengenai sasaran.
Bahaya Lupa WHERE #
WHERE pada UPDATE bersifat opsional — dan itulah masalahnya. Tanpa WHERE, SET diterapkan pada setiap baris tabel. Untuk melihat dampaknya tanpa korban, kita pakai pasangan BEGIN dan ROLLBACK yang membatalkan seluruh perubahan:
sqlite> BEGIN;
sqlite> UPDATE produk SET stok = 0;
sqlite> SELECT nama, stok FROM produk;
Pensil|0
Buku Tulis|0
Penghapus|0
Tas Sekolah|0
Botol Air|0
Rautan Pensil|0
Papan Tulis Kecil|0
sqlite> ROLLBACK;
sqlite> SELECT COUNT(*) FROM produk WHERE stok = 0;
1
sqlite>Setelah UPDATE tanpa WHERE, seluruh tujuh baris berstok 0 — termasuk Rautan Pensil yang tadinya NULL. Statement ROLLBACK memulihkan keadaan sebelum BEGIN, dan hanya Papan Tulis Kecil yang tetap berstok 0 karena memang dari sanalah.
DELETE #
Sintaks DELETE lebih ringkas: tabel dan kondisi:
sqlite> DELETE FROM produk WHERE harga > 50000;
sqlite> SELECT changes();
1
sqlite> SELECT COUNT(*) FROM produk;
6
sqlite> DELETE FROM produk WHERE harga > 1000000;
sqlite> SELECT changes();
0
sqlite>Tas Sekolah (85000) terhapus, sisanya enam baris. Delete kedua tidak menemukan sasaran dan kembali diam — pola yang sama dengan UPDATE.
Tanpa WHERE, DELETE mengosongkan seluruh tabel:
sqlite> DELETE FROM produk;
sqlite> SELECT changes();
6
sqlite> SELECT COUNT(*) FROM produk;
0
sqlite>DELETE FROM produk menghapus keenam baris yang tersisa, tetapi struktur tabel tetap ada — skema kolom dan constraint semuanya bertahan, siap diisi ulang. Ini berbeda dengan DROP TABLE yang menghapus tabel beserta strukturnya; perbedaan keduanya dibahas pada Chapter Mengubah Struktur Tabel.
Dengan empat statement DML lengkap — INSERT, SELECT, UPDATE, DELETE — siklus hidup data kita sudah utuh. Satu persoalan tersisa untuk Section ini: tabel yang sudah berdiri kadang perlu berubah bentuknya sendiri.