View adalah query SELECT yang disimpan dengan nama, lalu bisa dipanggil seperti tabel. Bayangin playlist pintar di aplikasi musik, misalnya "Paling sering diputar". Playlist itu gak menyimpan salinan lagu, cuma menyimpan aturannya. Setiap kali kamu buka, aturannya dijalankan lagi, jadi isinya selalu ikut kebiasaanmu yang terbaru. View juga begitu: yang disimpan query-nya, datanya diambil dari tabel asli setiap kali view dipanggil.
🧪 Tebakan cepat: kamu sudah bikin view
ringkasan_pesananyang menghitung belanja tiap pelanggan. Lalu Andi memesan Headset. Supaya Andi muncul di view, apakah view-nya perlu dibuat ulang? Tebak dulu, jawabannya ada di bagian "View menyimpan query, bukan data".
Tabel yang kita pakai
Dua tabel dari latihan. customers: Budi (1), Siti (2), Andi (3). orders:
| id | customer_id | product | amount |
|---|---|---|---|
| 1 | 1 | Laptop | 12000000 |
| 2 | 1 | Mouse | 150000 |
| 3 | 2 | Monitor | 3500000 |
| 4 | 2 | Keyboard | 500000 |
Andi belum pernah memesan.
Bikin view dengan CREATE VIEW
Ringkasan belanja tiap pelanggan butuh JOIN, COUNT, SUM dan GROUP BY. Daripada menulis query panjang itu di setiap halaman, simpan sekali sebagai view:
CREATE VIEW ringkasan_pesanan AS
SELECT
customers.name AS nama,
COUNT(orders.id) AS jumlah_pesanan,
SUM(orders.amount) AS total_belanja
FROM customers
INNER JOIN orders ON customers.id = orders.customer_id
GROUP BY customers.id, customers.name;
CREATE VIEW ringkasan_pesanan ASmemberi namaringkasan_pesananke querySELECTsesudahnya. Query-nya gak dijalankan sekarang, cuma disimpan.AS nama,AS jumlah_pesanan,AS total_belanjaadalah alias: nama baru untuk kolom hasil. Tanpa alias, kolom kedua bernamaCOUNT(orders.id), susah dipakai.INNER JOINcuma mengambil pelanggan yang punya pesanan. Andi belum memesan, jadi dia gak ikut.GROUP BYmengumpulkan pesanan per pelanggan, supayaCOUNTdanSUMdihitung per orang.
Sesudah itu, query panjang tadi cukup dipanggil dengan namanya:
SELECT * FROM ringkasan_pesanan;
| nama | jumlah_pesanan | total_belanja |
|---|---|---|
| Budi | 2 | 12150000 |
| Siti | 2 | 4000000 |
Alias juga bisa untuk tabel: FROM customers c INNER JOIN orders o ON c.id = o.customer_id membuat c dan o jadi nama pendek untuk customers dan orders, jadi c.name sama dengan customers.name.
View menyimpan query, bukan data
Andi memesan Headset:
INSERT INTO orders (customer_id, product, amount) VALUES (3, 'Headset', 750000);
SELECT * FROM ringkasan_pesanan;
| nama | jumlah_pesanan | total_belanja |
|---|---|---|
| Budi | 2 | 12150000 |
| Siti | 2 | 4000000 |
| Andi | 1 | 750000 |
Andi langsung muncul, tanpa membuat view-nya ulang. Itu jawaban tebakannya. Setiap kali kamu SELECT dari view, database menjalankan query yang tersimpan terhadap isi tabel saat itu. Yang disimpan database untuk ringkasan_pesanan cuma teks query CREATE VIEW tadi, bukan baris datanya.
Karena gak punya data sendiri, view juga gak bisa diisi langsung:
INSERT INTO ringkasan_pesanan VALUES ('Dewi', 1, 100000);
-- cannot modify ringkasan_pesanan because it is a view
Mau mengubah isinya? Ubah tabel aslinya, customers atau orders.
Mengubah dan menghapus view
DROP VIEW menghapus view. Datanya gak ikut terhapus, karena memang gak ada di view:
DROP VIEW ringkasan_pesanan;
DROP VIEW IF EXISTS ringkasan_pesanan; -- gak error kalau view-nya sudah gak ada
Membuat view dengan nama yang sudah dipakai menghasilkan error view ringkasan_pesanan already exists. Jadi untuk mengganti isi query-nya di SQLite, hapus dulu dengan DROP VIEW, lalu CREATE VIEW lagi. MySQL dan PostgreSQL punya jalan pintas CREATE OR REPLACE VIEW, tapi SQLite menolaknya dengan near "OR": syntax error.
📌 Kenapa pakai view
- Query panjang jadi pendek. Lima halaman yang butuh ringkasan cukup memanggil
SELECT * FROM ringkasan_pesanan. - Satu definisi. Kalau cara menghitungnya berubah, cukup ganti view-nya, bukan lima query di lima tempat.
- Membatasi kolom. View
pelanggan_publikyang cuma berisi nama dan kota bisa dibagikan tanpa membuka email dan nomor HP. Di MySQL dan PostgreSQL, hak akses bisa diberikan ke view-nya saja. SQLite gak punya sistem user, jadi di sana manfaatnya cuma kerapian. - View dijalankan ulang setiap dipanggil. Untuk laporan berat yang hasilnya mau disimpan, PostgreSQL punya
MATERIALIZED VIEW, yang benar-benar menyimpan hasilnya dan diperbarui denganREFRESH.
⚠️ Jebakan yang sering ketemu
LEFT JOINdi latihan. Andi ikut muncul dengan 0 pesanan, jadi hasilnya 3 baris. Latihannya minta pelanggan yang punya pesanan saja: pakaiINNER JOIN, hasilnya 2 baris.- Lupa alias. Tanpa
AS jumlah_pesanan, kolomnya bernamaCOUNT(orders.id), dan latihannya gak menemukan kolomjumlah_pesanan. Tiga kolom yang dicek:nama,jumlah_pesanan,total_belanja. - Cuma menjalankan
SELECT-nya. Hasilnya benar, tapi gak ada view yang tersimpan. Bungkus denganCREATE VIEW ringkasan_pesanan AS. CREATE VIEWdua kali. Erroralready exists.DROP VIEWdulu.
TL;DR: CREATE VIEW nama AS SELECT ... menyimpan sebuah query dengan nama, lalu SELECT * FROM nama menjalankannya seperti tabel. View menyimpan query, bukan data: perubahan di tabel asli langsung terlihat di view, dan view gak bisa di-INSERT. AS memberi alias ke kolom (COUNT(orders.id) AS jumlah_pesanan) atau ke tabel (customers c). Hapus dengan DROP VIEW, dan di SQLite ganti view dengan DROP VIEW lalu CREATE VIEW, karena CREATE OR REPLACE VIEW cuma ada di MySQL dan PostgreSQL.