Lompat ke konten
Kembali ke modul

Data: Database dan SQL · 3/7

SQL: membaca dan menulis data

SELECT, WHERE, ORDER BY, INSERT, UPDATE, DELETE. Kosakata setiap pekerjaan backend.

Baca 35 menit

Setelah pelajaran ini kamu bisa

  • Membaca dan menulis SELECT dengan WHERE, ORDER BY, dan LIMIT
  • Menambah, mengubah, dan menghapus row dengan aman
  • Selalu memakai parameter alih-alih penggabungan string
  • Menjelaskan kenapa NULL berperilaku tidak seperti nilai lain

SQL bersifat deklaratif: kamu mendeskripsikan hasil yang kamu inginkan, dan database yang menentukan cara mendapatkannya. Itu pergeseran yang sama seperti dari UI imperatif ke deklaratif di modul React.

sql
SELECT name, price_per_night
FROM venues
WHERE price_per_night > 200000
ORDER BY price_per_night DESC
LIMIT 2;
Output sungguhan dari SQLite proyek ini: Villa Sunset 850000, lalu Villa Rain 500000. Kos Melati seharga 150000 dikecualikan oleh WHERE-nya.

Klausanya selalu muncul dalam urutan ini, dan layak dihafal karena SQL tidak mengizinkanmu menulisnya dengan cara lain: SELECTFROMJOINWHEREGROUP BYHAVINGORDER BYLIMIT.

KlausaMenjawab
SELECTKolom mana yang saya mau kembali?
FROMDari tabel mana?
WHERERow mana? Menyaring row individual.
GROUP BYMeringkas row jadi kelompok
HAVINGKelompok mana? Menyaring setelah pengelompokan.
ORDER BYDalam urutan apa?
LIMITBerapa banyak?

Mengubah data

sql
INSERT INTO bookings (venue_id, guest, nights, paid)
VALUES (1, 'Dedi', 3, 1);

UPDATE bookings SET paid = 1 WHERE id = 2;

DELETE FROM bookings WHERE id = 2;

-- Insert or ignore a duplicate, instead of erroring.
-- This project uses exactly this so a double-click cannot fail:
INSERT INTO lesson_progress (user_id, lesson_id, completed_at)
VALUES (?, ?, ?)
ON CONFLICT (user_id, lesson_id) DO NOTHING;

Parameter, selalu

Ini paragraf terpenting di modul ini. Jangan pernah menyusun SQL dengan menggabungkan string. Kirim nilainya sebagai parameter dan biarkan driver-nya yang menanganinya.

ts
// ❌ SQL injection. The value becomes part of the query.
const name = request.body.name;
db.prepare("SELECT * FROM users WHERE name = '" + name + "'").all();
// name = "' OR '1'='1" returns every user.
// name = "'; DROP TABLE users;--" is worse.

// ✅ Parameterised. The value can never be read as SQL.
db.prepare("SELECT * FROM users WHERE name = ?").all(name);

// This is what every query in this project looks like:
run("DELETE FROM sessions WHERE token_hash = ?", hashToken(token));
query("SELECT lesson_id FROM lesson_progress WHERE user_id = ?", userId);
? itu bukan substitusi string. Database menerima query dan nilainya secara terpisah, jadi sebuah nilai tidak pernah di-parse sebagai sintaks.

NULL

NULL berarti "tidak diketahui", bukan "kosong". Membandingkan apa pun dengan yang tidak diketahui menghasilkan yang tidak diketahui, itu sebabnya = NULL tidak pernah cocok — bahkan dengan NULL lainnya.

sql
SELECT * FROM bookings WHERE cancelled_at = NULL;    -- always 0 rows
SELECT * FROM bookings WHERE cancelled_at IS NULL;    -- correct

-- NULL also disappears from aggregates and from NOT IN:
SELECT COUNT(*) FROM venues;              -- counts all rows
SELECT COUNT(owner_id) FROM venues;       -- counts rows where owner_id IS NOT NULL
Diverifikasi terhadap SQLite proyek ini: pada LEFT JOIN dari 3 venue dan 4 booking, COUNT(*) mengembalikan 5 dan COUNT(b.id) mengembalikan 4 — venue yang tidak punya pasangan menyumbang sebuah row tapi tanpa id booking.
Coba sendiri

Logika tiga nilai SQL, diimplementasikan. Inilah sebabnya NULL mengejutkan orang.

Hasil

Tekan Jalankan untuk melihat hasilnya.

Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.

Tugas praktik

Buka database proyek ini dengan node lalu jalankan tiga query: hitung jumlah user, daftar id pelajaran yang sudah kamu selesaikan, dan temukan row-mu sendiri di users berdasarkan nama memakai parameter ?. Lalu coba query nama yang sama dengan penggabungan string memakai nilai ' OR '1'='1 dan lihat berapa row yang kembali.

Hasil yang diharapkan

Query berparameter menemukan satu row; yang digabung string mengembalikan semua user.