Cara Membuat View di MySQL

view itu tabel virtual yang dihasilkan dari query select. view tidak nyimpen data fisik, data diambil dari tabel asli tiap kali view diakses. view ini sangat berkaitan dengan fungsi agregat count, sum, dan avg karena sering dipakai buat nyederhanain laporan yang melibatkan kalkulasi.
saya mulai serius pakai view waktu query laporan di aplikasi sudah terlalu panjang buat dibaca, lebih dari 10 baris join yang harus ditulis ulang di tiga tempat berbeda. setelah dipindahin ke view, kode aplikasi menyusut drastis dan siapa pun di tim bisa pakai query yang sama tanpa takut salah ketik.
1. Kenapa Pakai View?
- Sederhanain query kompleks, simpan query join yang rumit sebagai view
- Keamanan, kasih akses ke view tanpa perlu akses ke tabel asli
- Konsistensi, semua orang pakai query yang sama persis
- Abstraksi, struktur tabel bisa berubah tanpa ngubah query user
contoh keamanan paling umum: tabel users punya kolom password dan email. daripada ngasih akses tabel itu ke tim laporan, buat view yang cuma menampilkan nama dan jumlah_transaksi. tim laporan dapat datanya, kolom sensitif tetap aman.
2. Membuat View
sintaks dasarnya CREATE VIEW nama_view AS <query>, lengkapnya ada opsi MySQL:
CREATE
[OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
[DEFINER = user] [SQL SECURITY { DEFINER | INVOKER }]
VIEW nama_view AS <select_statement>
[WITH [CASCADED | LOCAL] CHECK OPTION]
contoh paling simpel:
CREATE VIEW laporan_penjualan AS
SELECT
p.id,
p.tanggal,
c.nama as customer,
pr.nama as produk,
d.jumlah,
d.harga,
d.jumlah * d.harga as total
FROM penjualan p
JOIN customer c ON p.customer_id = c.id
JOIN penjualan_detail d ON p.id = d.penjualan_id
JOIN produk pr ON d.produk_id = pr.id;
sekali jalan, query join 4 tabel di atas jadi tersimpan dengan nama laporan_penjualan. kalau tidak tulis ALGORITHM, defaultnya UNDEFINED, MySQL akan pilih MERGE kalau bisa karena lebih cepat dan bisa pakai index, kalau tidak bisa baru pakai TEMPTABLE (hasil view dimasukin ke temporary table dulu).
3. Menggunakan View
pemakaiannya sama persis kayak tabel biasa:
SELECT * FROM laporan_penjualan;
SELECT customer, SUM(total) as total_belanja
FROM laporan_penjualan
GROUP BY customer;
yang menarik, data di view selalu fresh. begitu ada penjualan baru di tabel asli, hasil view langsung ikut berubah, tidak perlu refresh apa pun.
4. View dengan Kondisi
view juga bisa menyaring data dari awal:
CREATE VIEW produk_aktif AS
SELECT * FROM produk WHERE aktif = 1;
CREATE VIEW penjualan_bulan_ini AS
SELECT * FROM penjualan
WHERE MONTH(tanggal) = MONTH(CURDATE())
AND YEAR(tanggal) = YEAR(CURDATE());
dengan begini, tim marketing cukup SELECT * FROM produk_aktif, dijamin tidak akan pernah lihat produk yang sudah di-nonaktifkan.
5. Updatable View
ternyata view tidak cuma buat baca, view sederhana juga bisa di-insert, update, dan delete, dan perubahannya diteruskan ke tabel asli:
-- insert lewat view
INSERT INTO produk_aktif (nama, harga, aktif)
VALUES ('Mouse Wireless', 150000, 1);
-- update lewat view
UPDATE produk_aktif SET harga = 145000 WHERE nama = 'Mouse Wireless';
-- delete lewat view
DELETE FROM produk_aktif WHERE nama = 'Mouse Wireless';
syaratnya view harus updatable, artinya ada relasi satu-satu antara baris view dan baris tabel asli. praktisnya, hindari GROUP BY, DISTINCT, HAVING, UNION, LIMIT, fungsi agregat (SUM, COUNT), subquery di select list, atau join yang bikin baris jadi ambigu. kalau view cuma SELECT * FROM satu_tabel WHERE kondisi dan kolomnya map langsung ke kolom tabel, biasanya aman. view yang pakai TEMPTABLE juga otomatis tidak updatable.
6. WITH CHECK OPTION
ada jebakan menarik waktu update lewat view ber-filter. tanpa check option, data yang melanggar kondisi tetap bisa masuk tapi langsung tidak kelihatan:
-- tanpa check option
CREATE VIEW produk_aktif AS
SELECT * FROM produk WHERE aktif = 1;
-- ini jalan! tapi barisnya tidak kelihatan di view
UPDATE produk_aktif SET aktif = 0 WHERE id = 5;
baris id 5 jadi “hilang” dari view, padahal masuk. biar dicegah, tambahkan WITH CHECK OPTION:
CREATE OR REPLACE VIEW produk_aktif AS
SELECT * FROM produk WHERE aktif = 1
WITH CHECK OPTION;
-- sekarang error: CHECK OPTION failed
UPDATE produk_aktif SET aktif = 0 WHERE id = 5;
rule sederhananya, kalau view bakal dipakai buat nulis data, selalu pasang WITH CHECK OPTION. defaultnya CASCADED, artinya cek juga ke view induk di bawahnya. LOCAL cuma cek view itu sendiri plus view yang punya CHECK OPTION. cek statusnya lewat:
SELECT TABLE_NAME, CHECK_OPTION FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'produk_aktif';
-- nilai: NONE, CASCADED, atau LOCAL
7. Update dan Hapus View
cara ubah view pakai CREATE OR REPLACE VIEW, di MySQL ALTER VIEW juga ada dan fungsinya sama (alias). buat hapus pakai DROP VIEW:
-- Update view (ganti definisi)
CREATE OR REPLACE VIEW laporan_penjualan AS
SELECT p.id, p.tanggal, c.nama as customer,
SUM(d.jumlah * d.harga) as total
FROM penjualan p
JOIN customer c ON p.customer_id = c.id
JOIN penjualan_detail d ON p.id = d.penjualan_id
GROUP BY p.id, p.tanggal, c.nama;
-- alternatif pakai ALTER (sama saja)
ALTER VIEW laporan_penjualan AS
SELECT p.id, p.tanggal, c.nama as customer,
SUM(d.jumlah * d.harga) as total
FROM penjualan p
JOIN customer c ON p.customer_id = c.id
JOIN penjualan_detail d ON p.id = d.penjualan_id
GROUP BY p.id, p.tanggal, c.nama;
-- Lihat definisi view
SHOW CREATE VIEW laporan_penjualan;
-- Hapus view
DROP VIEW IF EXISTS laporan_penjualan;
8. View dan Performa
perlu diingat, view itu cuma query tersimpan, bukan hasil tersimpan. jadi:
- kalau pakai
MERGE, kondisiWHEREdi luar view digabung ke dalam view pakaiAND, jadiSELECT * FROM view_besar WHERE tanggal = '2026-08-01'bisa tetap pakai index tabel asli. cek pakaiEXPLAIN, kalau kelihatan tabel asli langsung berarti MERGE jalan. - kalau pakai
TEMPTABLE(terjadi kalau adaDISTINCT,GROUP BY,LIMIT,UNION, agregat), MySQL harus masukin semua baris view ke temporary table dulu baru di-filter, ini yang bikin lambat dan tidak bisa pakai index.TEMPTABLEjuga bikin view tidak updatable. - view di atas view (nested view) bikin query makin berlapis, hindari kalau bisa
- kalau butuh hasil yang benar-benar tersimpan fisik, mysql tidak punya materialized view, emulasinya pakai tabel biasa yang di-refresh lewat event scheduler atau trigger
buat view yang ringan, dan jangan ragu cek EXPLAIN kalau ada query yang tiba-tiba lambat setelah diubah ke view. kalau EXPLAIN muncul <derived> atau temptable, berarti sedang tidak MERGE.
9. Studi Kasus: Laporan Penjualan Bulanan
kombinasi view plus agregat buat laporan bulanan yang siap pakai:
-- view laporan ringkas
CREATE VIEW laporan_penjualan_bulanan AS
SELECT
DATE_FORMAT(p.tanggal, '%Y-%m') as bulan,
c.nama as customer,
COUNT(d.id) as jumlah_transaksi,
SUM(d.jumlah * d.harga) as total_belanja
FROM penjualan p
JOIN customer c ON p.customer_id = c.id
JOIN penjualan_detail d ON p.id = d.penjualan_id
GROUP BY bulan, c.nama;
-- tinggal panggil
SELECT * FROM laporan_penjualan_bulanan
WHERE bulan = '2026-08'
ORDER BY total_belanja DESC;
sekali bikin, query laporan bulanan jadi satu baris, dan dipakai ulang di mana pun, dari dashboard sampai export excel.
Kesimpulan
- view itu tabel virtual dari hasil query, data aslinya tetap di tabel sumber
CREATE VIEWbuat bikin,CREATE OR REPLACE VIEWbuat ubah,DROP VIEWbuat hapus- view menyederhanakan query join berulang dan bikin laporan konsisten
- view juga alat keamanan, batasi kolom sensitif dari user tertentu
- view sederhana bisa di-insert, update, delete, dan pasang
WITH CHECK OPTIONbiar aman - mysql tidak punya materialized view, performa view tergantung query di dalamnya
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Apa itu view di MySQL?
view itu tabel virtual hasil query select. view tidak nyimpen data sendiri, tiap kali diakses dia jalanin query-nya ke tabel asli. fungsinya nyederhanain query kompleks, ngamanin data, dan bikin laporan lebih konsisten.
Apa bedanya view dan tabel biasa?
tabel nyimpen data fisik di disk, view cuma nyimpen query. jadi kalau data di tabel asli berubah, hasil view langsung ikut berubah tanpa perlu diupdate manual. ukuran view juga kecil karena cuma definisi.
Apakah view di MySQL bisa di-insert, update, atau delete?
bisa, selama view-nya updatable, artinya query-nya tidak pakai group by, distinct, union, join ke banyak tabel yang bikin baris ambigu, atau fungsi agregat. kalau cuma select sederhana dari satu tabel, biasanya aman.
Bagaimana cara update atau hapus view?
update pakai CREATE OR REPLACE VIEW, hapus pakai DROP VIEW IF EXISTS nama_view, dan lihat definisinya pakai SHOW CREATE VIEW nama_view.
Apa itu WITH CHECK OPTION di view?
WITH CHECK OPTION maksa semua data yang masuk lewat view memenuhi kondisi where di view. tanpa ini, data yang tidak lolos kondisi tetap bisa masuk tapi langsung tidak kelihatan di view, bikin bingung.
Apakah MySQL punya materialized view?
tidak. mysql cuma punya view biasa yang dihitung tiap kali diakses. kalau butuh hasil yang disimpan fisik, emulasi pakai tabel biasa yang di-refresh pakai event scheduler atau trigger.
Kenapa view bisa bikin query lambat?
karena view itu query di dalam query. kalau view-nya join banyak tabel lalu di-join lagi dengan filter di luar, mysql harus proses semua baris dulu. solusinya sederhanakan view, jangan menumpuk view di atas view.

