View adalah objek skema berupa query bernama yang tersimpan di server, sehingga
pernyataan SELECT yang panjang dapat dipanggil kembali seperti memanggil
tabel biasa. Topik ini membahas pembuatan view, view yang dapat diperbarui
(updatable view), pengaman WITH CHECK OPTION, batasan view yang memuat
agregasi, serta pengelolaan definisinya. Setelah mengikuti topik ini, query
berulang dapat dibungkus menjadi objek yang terdokumentasi dan konsisten di
seluruh aplikasi.
Membuat dan membaca view#
CREATE VIEW menyimpan definisi query di bawah sebuah nama, dan setiap
pembacaan nama itu menjalankan kembali querynya. Baris yang dikembalikan selalu
mengikuti data tabel dasarnya saat itu, sehingga view berperilaku seperti
jendela yang transparan, bukan salinan data yang membeku.
Jalankan persiapan berikut, kemudian buat view pertama.
-- tidak-dijalankan
-- Skrip persiapan topik view: basis data perpustakaan
DROP DATABASE IF EXISTS perpustakaan;
CREATE DATABASE perpustakaan;
USE perpustakaan;
CREATE TABLE anggota (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL
);
CREATE TABLE buku (
id INT AUTO_INCREMENT PRIMARY KEY,
judul VARCHAR(200) NOT NULL,
penulis VARCHAR(100) NOT NULL,
stok INT NOT NULL DEFAULT 0
);
CREATE TABLE peminjaman (
id INT AUTO_INCREMENT PRIMARY KEY,
anggota_id INT NOT NULL,
buku_id INT NOT NULL,
tanggal_pinjam DATE NOT NULL,
jatuh_tempo DATE NOT NULL,
tanggal_kembali DATE NULL,
FOREIGN KEY (anggota_id) REFERENCES anggota(id),
FOREIGN KEY (buku_id) REFERENCES buku(id)
);
INSERT INTO anggota (nama) VALUES
('Ali'), ('Budi'), ('Citra'), ('Dewi'), ('Eka');
INSERT INTO buku (judul, penulis, stok) VALUES
('Dasar Astronomi untuk Pemula', 'Hartono', 3),
('Sejarah Maritim Nusantara', 'Wijaya', 2),
('Panduan Menanam Sayuran', 'Santoso', 4),
('Pengantar Fisika Klasik', 'Kusuma', 1),
('Cerita Rakyat Nusantara', 'Lestari', 3),
('Ilmu Gizi Sehari-hari', 'Pratiwi', 2);
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam, jatuh_tempo, tanggal_kembali) VALUES
(1, 1, '2026-05-02', '2026-05-16', '2026-05-15'),
(1, 2, '2026-05-02', '2026-05-16', '2026-05-14'),
(1, 3, '2026-06-01', '2026-06-15', '2026-06-20'),
(2, 4, '2026-05-10', '2026-05-24', '2026-05-22'),
(2, 5, '2026-06-03', '2026-06-17', NULL),
(2, 6, '2026-06-03', '2026-06-17', '2026-06-10'),
(3, 1, '2026-05-20', '2026-06-03', '2026-06-01'),
(3, 4, '2026-06-05', '2026-06-19', NULL),
(4, 2, '2026-05-25', '2026-06-08', '2026-06-07'),
(4, 3, '2026-06-12', '2026-06-26', NULL),
(5, 4, '2026-06-14', '2026-06-28', '2026-06-27'),
(5, 5, '2026-06-18', '2026-07-02', NULL),
(3, 6, '2026-07-01', '2026-07-15', NULL);# membuat ulang basis data perpustakaan dari nol
mysql -u root < persiapan-view.sql# membuat view pinjam_aktif lalu membacanya seperti tabel biasa
mysql -t -u root perpustakaan <<'SQL'
DROP VIEW IF EXISTS pinjam_aktif;
CREATE VIEW pinjam_aktif AS
SELECT p.id, a.nama AS anggota, b.judul AS buku, p.tanggal_pinjam, p.jatuh_tempo
FROM peminjaman AS p
JOIN anggota AS a ON a.id = p.anggota_id
JOIN buku AS b ON b.id = p.buku_id
WHERE p.tanggal_kembali IS NULL;
SELECT * FROM pinjam_aktif ORDER BY id;
SQL+----+---------+-------------------------+----------------+-------------+
| id | anggota | buku | tanggal_pinjam | jatuh_tempo |
+----+---------+-------------------------+----------------+-------------+
| 5 | Budi | Cerita Rakyat Nusantara | 2026-06-03 | 2026-06-17 |
| 8 | Citra | Pengantar Fisika Klasik | 2026-06-05 | 2026-06-19 |
| 10 | Dewi | Panduan Menanam Sayuran | 2026-06-12 | 2026-06-26 |
| 12 | Eka | Cerita Rakyat Nusantara | 2026-06-18 | 2026-07-02 |
| 13 | Citra | Ilmu Gizi Sehari-hari | 2026-07-01 | 2026-07-15 |
+----+---------+-------------------------+----------------+-------------+Query tiga tabel dengan saringan WHERE kini cukup dipanggil sebagai
SELECT * FROM pinjam_aktif. Pola DROP VIEW IF EXISTS sebelum CREATE VIEW
membuat skrip penyiapan dapat dijalankan ulang tanpa error, karena nama view
yang sudah ada dihapus terlebih dahulu.
Pembaruan melalui view#
View yang hanya merujuk satu tabel tanpa agregasi dapat diperbarui. Pernyataan
INSERT, UPDATE, dan DELETE yang ditujukan ke view diterjemahkan oleh
MySQL menjadi pembaruan pada tabel dasarnya. Syaratnya sederhana, yaitu kolom
yang dipetakan harus jelas sumber tabelnya.
# view satu tabel dapat diperbarui seperti tabel biasa
mysql -t -u root perpustakaan <<'SQL'
DROP VIEW IF EXISTS buku_tersedia;
CREATE VIEW buku_tersedia AS
SELECT id, judul, penulis, stok
FROM buku
WHERE stok > 0;
UPDATE buku_tersedia SET stok = stok + 2 WHERE judul = 'Ilmu Gizi Sehari-hari';
SELECT id, judul, stok FROM buku_tersedia ORDER BY id;
SQL+----+------------------------------+------+
| id | judul | stok |
+----+------------------------------+------+
| 1 | Dasar Astronomi untuk Pemula | 3 |
| 2 | Sejarah Maritim Nusantara | 2 |
| 3 | Panduan Menanam Sayuran | 4 |
| 4 | Pengantar Fisika Klasik | 1 |
| 5 | Cerita Rakyat Nusantara | 3 |
| 6 | Ilmu Gizi Sehari-hari | 4 |
+----+------------------------------+------+Pembaruan melalui view menulis ke tabel buku, dan efeknya langsung terlihat.
Namun ada celah yang perlu diketahui. Sisipan melalui view dengan saringan
WHERE dapat menghasilkan baris yang tidak lolos saringan tersebut, sehingga
barisnya masuk ke tabel dasar tetapi tidak pernah muncul di view.
# sisipan melalui view tanpa WITH CHECK OPTION menghasilkan baris tersembunyi
mysql -t -u root perpustakaan <<'SQL'
INSERT INTO buku_tersedia (id, judul, penulis, stok) VALUES (7, 'Ensiklopedia Batu', 'Nugraha', 0);
SELECT id, judul, stok FROM buku_tersedia ORDER BY id;
SQL+----+------------------------------+------+
| id | judul | stok |
+----+------------------------------+------+
| 1 | Dasar Astronomi untuk Pemula | 3 |
| 2 | Sejarah Maritim Nusantara | 2 |
| 3 | Panduan Menanam Sayuran | 4 |
| 4 | Pengantar Fisika Klasik | 1 |
| 5 | Cerita Rakyat Nusantara | 3 |
| 6 | Ilmu Gizi Sehari-hari | 4 |
+----+------------------------------+------+# baris baru itu nyata pada tabel dasarnya
mysql -t -u root perpustakaan -e "SELECT id, judul, stok FROM buku ORDER BY id;"+----+------------------------------+------+
| id | judul | stok |
+----+------------------------------+------+
| 1 | Dasar Astronomi untuk Pemula | 3 |
| 2 | Sejarah Maritim Nusantara | 2 |
| 3 | Panduan Menanam Sayuran | 4 |
| 4 | Pengantar Fisika Klasik | 1 |
| 5 | Cerita Rakyat Nusantara | 3 |
| 6 | Ilmu Gizi Sehari-hari | 4 |
| 7 | Ensiklopedia Batu | 0 |
+----+------------------------------+------+Buku bernomor tujuh berstok nol lolos masuk ke tabel buku, tetapi tidak tampak
di buku_tersedia karena saringannya menuntut stok > 0. Keadaan seperti ini
membingungkan pembaca laporan, karena data tampak hilang tanpa jejak.
WITH CHECK OPTION#
WITH CHECK OPTION menutup celah tersebut. Dengan opsi ini, setiap sisipan dan
pembaruan melalui view wajib menghasilkan baris yang tetap memenuhi syarat
WHERE view itu, dan server menolak sisanya dengan error 1369.
# WITH CHECK OPTION menolak baris yang tidak lolos syarat view
mysql -u root perpustakaan <<'SQL'
DROP VIEW IF EXISTS buku_tersedia;
CREATE VIEW buku_tersedia AS
SELECT id, judul, penulis, stok
FROM buku
WHERE stok > 0
WITH CHECK OPTION;
SQL
mysql -u root perpustakaan -e "INSERT INTO buku_tersedia (id, judul, penulis, stok) VALUES (8, 'Atlas Hujan Tropis', 'Mahendra', 0);"ERROR 1369 (HY000) at line 1: CHECK OPTION failed 'perpustakaan.buku_tersedia'Tanpa opsi ini, sisipan serupa akan lolos dan menghasilkan baris tersembunyi seperti pada bagian sebelumnya. Secara bawaan pemeriksaan berlaku bertingkat (cascaded), yaitu syarat view ini dan seluruh view lain yang menjadi dasarnya diperiksa sekaligus.
View yang tidak dapat diperbarui#
View yang mengandung agregasi tidak lagi punya pemetaan baris yang jelas ke
tabel dasarnya, sehingga tidak dapat diperbarui. View statistik_buku
berikut memakai GROUP BY, dan percobaan pembaruannya ditolak server.
# view dengan GROUP BY tidak dapat diperbarui
mysql -u root perpustakaan <<'SQL'
DROP VIEW IF EXISTS statistik_buku;
CREATE VIEW statistik_buku AS
SELECT penulis, COUNT(*) AS jumlah_judul, SUM(stok) AS total_stok
FROM buku
GROUP BY penulis;
SQL
mysql -u root perpustakaan -e "UPDATE statistik_buku SET total_stok = 9 WHERE penulis = 'Nugraha';"ERROR 1288 (HY000) at line 1: The target table statistik_buku of the UPDATE is not updatableSelain GROUP BY, view menjadi tidak dapat diperbarui apabila definisinya
memuat fungsi agregat, DISTINCT, HAVING, UNION, atau subquery pada daftar
kolomnya. View semacam itu tetap sangat berguna sebagai
lapisan pembacaan, hanya saja perubahannya harus ditulis ke tabel dasarnya.
Mengelola view#
Definisi view dapat diganti dengan ALTER VIEW tanpa menghapus hak akses dan
tanpa memaksa pemanggilnya menyesuaikan nama. Penghapusan memakai DROP VIEW,
dan status seluruh view dapat diperiksa lewat kamus data
information_schema.views.
# definisi view dapat diganti tanpa mengubah nama objeknya
mysql -t -u root perpustakaan <<'SQL'
ALTER VIEW statistik_buku AS
SELECT penulis, SUM(stok) AS total_stok
FROM buku
GROUP BY penulis;
SELECT * FROM statistik_buku ORDER BY penulis;
SQL+---------+------------+
| penulis | total_stok |
+---------+------------+
| Hartono | 3 |
| Kusuma | 1 |
| Lestari | 3 |
| Nugraha | 0 |
| Pratiwi | 4 |
| Santoso | 4 |
| Wijaya | 2 |
+---------+------------+# status view terdaftar pada kamus data
mysql -t -u root perpustakaan -e "SELECT table_name, is_updatable FROM information_schema.views WHERE table_schema = 'perpustakaan' ORDER BY table_name;"+----------------+--------------+
| TABLE_NAME | IS_UPDATABLE |
+----------------+--------------+
| buku_tersedia | YES |
| pinjam_aktif | YES |
| statistik_buku | NO |
+----------------+--------------+Kolom IS_UPDATABLE melaporkan sifat setiap view. buku_tersedia bernilai YES
karena merujuk satu tabel tanpa agregasi, dan pinjam_aktif juga bernilai YES
karena join tanpa agregasi tetap mempertahankan pemetaan barisnya. UPDATE
melalui view join diterima selama perubahan menyentuh satu tabel dasar saja.
INSERT dan DELETE pada view multi-tabel ditolak karena barisnya melibatkan
lebih dari satu tabel dasar sekaligus. statistik_buku
mengelompokkan baris dengan GROUP BY, sehingga pemetaan barisnya hilang dan
nilainya NO.
Kesalahan umum#
Kesalahan pertama adalah menganggap view sebagai tabel fisik yang mempercepat
query. Pembacaan view menjalankan kembali query dasarnya, sehingga view di atas
query lambat tetap lambat. Apabila hasil perantara memang perlu dibekukan,
CREATE TABLE ... AS SELECT atau tabel ringkasan yang diisi berkala lebih
tepat daripada view.
Kesalahan kedua adalah menyisipkan data melalui view bersyarat tanpa
WITH CHECK OPTION, yang menghasilkan baris tersembunyi seperti telah
didemonstrasikan. Kesalahan ketiga adalah mencoba memperbarui view agregat,
yang selalu berujung error 1288. Perbaikannya bukan mengubah view, melainkan
menulis pembaruan ke tabel dasarnya. Kesalahan keempat adalah mengabaikan pola
DROP VIEW IF EXISTS pada skrip penyiapan, sehingga skrip hanya bisa dijalankan
sekali dan gagal pada eksekusi berikutnya.
Ringkasan#
- View adalah query bernama yang tersimpan sebagai objek skema, dan setiap pembacaannya menjalankan kembali query dasarnya terhadap data terkini.
- View satu tabel tanpa agregasi dapat diperbarui, dan
WITH CHECK OPTIONmenolak sisipan maupun pembaruan yang menghasilkan baris di luar syaratnya. - View dengan agregasi,
DISTINCT,UNION, atau subquery pada daftar kolomnya tidak dapat diperbarui dan melaporkan dirinya sebagaiIS_UPDATABLE = NO, sedangkan view join tanpa agregasi menerimaUPDATEpada satu tabel dasar dalam satu pernyataan. - Definisi view dikelola dengan
ALTER VIEWdanDROP VIEW, dengan polaDROP VIEW IF EXISTSagar skrip tetap dapat dijalankan ulang.
Referensi#
- CREATE VIEW Statement — MySQL 8.0 Reference Manual
— Sintaks pembuatan view,
WITH CHECK OPTION, dan aturan view yang dapat diperbarui. - ALTER VIEW Statement — MySQL 8.0 Reference Manual — Penggantian definisi view tanpa menghapus objeknya.