Belajar dengan membaca secara berurutan

UPDATE / DELETE dengan Subquery dan JOIN

Memakai tabel stock dan tabel kedatangan stock_in, pelajari bulk update dengan correlated subquery, UPDATE … FROM join, dan DELETE dengan kondisi subquery, plus cara memeriksa jumlah baris yang terpengaruh — semua langsung dipraktikkan di browser.

Data yang akan kita pakai — stock dan stock_in

Artikel ini membahas gaya penulisan yang lebih lanjut — memperbarui dan menghapus dengan nilai dari tabel lain atau hasil agregat.

Spesifiknya, tiga pola: update yang nilainya dihitung oleh correlated subquery (subquery yang SELECT internalnya merujuk kolom dari baris luar, sehingga dievaluasi per baris), update bergaya join via UPDATE … FROM terhadap tabel lain, dan pernyataan DELETE dengan subquery di klausa WHERE.

Sebelum latihan, lihat dulu definisi kolom dan data sampel dari kedua tabel — stock dan stock_in.

① Jalankan PRAGMA table_info(stock); untuk memeriksa nama kolom, tipe, dan primary key dari stock.

② Pratinjau kedua tabel dengan SELECT * FROM stock LIMIT 5; dan SELECT * FROM stock_in;. Perhatikan bahwa stock_in berisi sku yang tidak ada di sisi stock.

SQL Editor

Jalankan query untuk melihat hasil

Pakai correlated subquery untuk update dengan nilai dari tabel lain

Menulis UPDATE table SET col = (SELECT ... WHERE subquery.key = table.key) mengevaluasi SELECT internal sekali untuk setiap baris target dan menulis hasilnya ke kolom.

Karena SELECT internalnya merujuk kolom dari target UPDATE luar (stock.sku), bentuk ini disebut correlated subquery.

Jebakannya adalah: untuk baris stock yang tidak punya baris yang cocok di stock_in, SELECT internal mengembalikan NULL.

-- Tanpa COALESCE: qty ditimpa NULL untuk sku yang tidak punya pasangan
UPDATE stock
SET qty = qty + (SELECT SUM(add_qty) FROM stock_in WHERE stock_in.sku = stock.sku);
Update correlated subquery tanpa COALESCE
baris stockCorrelated subqueryqty baruA001 qty=120SUM(add_qty)WHERE sku='A001'= 50120 + 50 = 170A002 qty=60tidak cocokSUM = NULL60 + NULL= NULLA004 qty=15SUM(add_qty)WHERE sku='A004'= 10015 + 100 = 115
Untuk setiap baris target UPDATE, sku baris itu diteruskan ke SELECT internal untuk menghitung sum. Kalau tidak ada baris yang cocok, SUM mengembalikan NULL dan qty + NULL menjadi NULL — nilai stok dirusak.

Kalau kamu menjalankan qty = qty + (SELECT ...) apa adanya, baris yang tidak punya kedatangan akan tertulis NULL pada qty-nya.

Untuk mencegah ini, bungkus subquery dengan COALESCE(subquery, 0) agar NULL berubah jadi 0, atau persempit target dengan WHERE EXISTS (...) supaya kamu hanya menyentuh baris yang benar-benar punya kedatangan.

-- Pratinjau dulu nilai pasca-update dengan SELECT (stock belum berubah)
SELECT sku, qty,
  qty + (SELECT COALESCE(SUM(add_qty), 0) FROM stock_in WHERE stock_in.sku = stock.sku) AS new_qty
FROM stock;

-- Setelah puas, ganti ke UPDATE (COALESCE mengubah NULL jadi 0)
UPDATE stock
SET qty = qty + (SELECT COALESCE(SUM(add_qty), 0) FROM stock_in WHERE stock_in.sku = stock.sku);

Bayangkan kebutuhannya: "refleksikan jumlah dari tabel kedatangan stock_in ke qty baris stock yang cocok." (Jalankan dengan benar dan penjelasannya akan muncul.)

① Pertama jalankan SELECT sku, qty FROM stock ORDER BY sku; untuk melihat keadaan sebelum update apa pun.

② Tulis versi COALESCE: update correlated subquery yang menambahkan jumlah stock_in.add_qty ke stock.qty. Untuk sku yang tidak punya baris pasangan di stock_in, perlakukan NULL sebagai 0 supaya nilainya tetap. Jalankan SELECT lagi setelahnya untuk mengonfirmasi.

③ Lalu tulis versi EXISTS: update yang menggunakan WHERE EXISTS (...) untuk membatasi target ke "baris yang punya kedatangan". Jalankan SELECT lagi dan perhatikan A001 / A004 menerima kedatangan yang sama untuk kedua kalinya — terhitung ganda.

SQL Editor

Jalankan query untuk melihat hasil

UPDATE … FROM: gabungkan tabel lain dan perbarui

Menulis UPDATE table SET col = value FROM other_table WHERE join_condition memungkinkan kamu men-join target UPDATE dengan tabel yang disebut di FROM dan memperbarui sekali jalan, dengan langsung merujuk kolom sisi join di SET.

-- Contoh UPDATE … FROM: naikkan price 10 hanya untuk item yang punya kedatangan
UPDATE stock
SET price = price + 10
FROM stock_in
WHERE stock.sku = stock_in.sku;

-- Hanya sku yang ter-join (A001 / A004) yang price-nya naik
SELECT sku, price FROM stock ORDER BY sku;

Baris di stock yang tidak punya pasangan di sisi FROM (stock_in) gagal pada kondisi join di WHERE dan otomatis keluar dari target update.

Berbeda dengan bentuk correlated subquery, kamu tidak perlu berjaga-jaga terhadap NULL secara terpisah.

Update bergaya join dengan UPDATE … FROM
WHEREstock.sku = stock_in.skujoinstock(target)stock_in(sisi FROM)A001 / A004ter-join → diperbaruiA002 / A003 / A005tidak join → dilewati
Kondisi join WHERE menghubungkan stock dan stock_in, dan hanya baris yang ter-join yang qty-nya diperbarui. Baris yang tidak ter-join gagal di WHERE dan dikecualikan.

Bayangkan kebutuhannya: "lakukan refleksi stok yang sama dengan Latihan 1, tetapi tulis lebih ringkas dengan UPDATE … FROM."

① Tempatkan stock sebagai target update dan stock_in di sisi FROM, join pada sku, dan tulis UPDATE … FROM yang menambahkan add_qty ke qty.

② Akhiri skrip dengan SELECT sku, qty FROM stock ORDER BY sku; dan konfirmasi bahwa hanya sku yang ter-join (A001 / A004) yang stoknya naik.

SQL Editor

Jalankan query untuk melihat hasil

DELETE dengan kondisi subquery, dan memeriksa jumlah baris yang terpengaruh

Kamu bisa menaruh subquery di WHERE dari DELETE, seperti DELETE FROM table WHERE col IN (SELECT ...) atau WHERE EXISTS (SELECT ...).

Ini memungkinkan penghapusan yang tidak bisa diekspresikan dengan nilai tetap: "hapus hanya baris yang ada / tidak ada di tabel lain," atau "hapus baris yang hasil agregatnya memenuhi suatu kondisi."

Penghapusan bersifat merusak dan tidak bisa diulang, jadi praktik standar di produksi adalah menjalankan dulu WHERE yang sama di dalam SELECT COUNT(*) untuk memeriksa jumlah baris yang terpengaruh, lalu menulis ulang menjadi DELETE.

Setelah eksekusi, verifikasi dengan SELECT COUNT(*) FROM table; untuk mengonfirmasi bahwa jumlah baris yang tersisa sesuai dengan yang kamu harapkan.

-- Periksa dulu apa yang akan dihapus: item di bawah harga rata-rata (stock belum berubah)
SELECT sku, name, price FROM stock
WHERE price < (SELECT AVG(price) FROM stock);

-- Setelah puas, ganti ke DELETE lalu periksa jumlah yang tersisa
DELETE FROM stock
WHERE price < (SELECT AVG(price) FROM stock);
SELECT COUNT(*) AS remaining FROM stock;

Bayangkan kebutuhannya: "hapus dari stock kandidat penghentian — sku yang qty-nya 0 dan tidak ada kedatangan terjadwal di stock_in." Karena ini latihan terakhir artikel, kamu akan melakukan penghapusan destruktif terhadap tabel hidup.

① Tulis DELETE dengan kondisi subquery yang menghapus baris dari stock di mana qty adalah 0 dan sku tidak ada di stock_in.

② Setelah delete, jalankan SELECT COUNT(*) AS remaining FROM stock; untuk memastikan berapa baris yang tersisa. Kamu juga bisa memakai SELECT * FROM stock ORDER BY sku; untuk memverifikasi bahwa A005 (Glue / qty 0 / tidak ada kedatangan) sudah hilang.

SQL Editor

Jalankan query untuk melihat hasil
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Kalau kamu menjalankan UPDATE stock SET qty = qty + (SELECT SUM(add_qty) FROM stock_in WHERE stock_in.sku = stock.sku); tanpa WHERE EXISTS (...), apa yang terjadi pada qty untuk sku yang tidak punya baris pasangan di stock_in?

Soal 2Pada UPDATE stock SET qty = stock.qty + stock_in.add_qty FROM stock_in WHERE stock.sku = stock_in.sku;, bagaimana baris stock yang tidak punya pasangan di stock_in ditangani?

Soal 3Mana prosedur paling tepat untuk menjalankan DELETE berbasis subquery dengan aman di produksi?