View

Query tersimpan sebagai tabel virtual dan batas view yang dapat diperbarui.

Daftar isi

Sebuah view adalah pernyataan SELECT yang diberi nama dan disimpan sebagai objek basis data, sehingga query yang panjang cukup ditulis satu kali lalu dipanggil seperti tabel biasa. Topik ini membahas pembuatan view dengan CREATE VIEW pada skema perpustakaan, pemakaiannya dalam query lain, batas pembaruannya pada SQLite, keluar dengan trigger INSTEAD OF, serta penghapusannya dengan DROP VIEW. Seluruh blok SQL bersifat mandiri karena memuat CREATE dan INSERT-nya sendiri, sehingga setiap blok dapat dijalankan ulang dengan sqlite3 :memory: dan menghasilkan keluaran yang sama.

View sebagai query tersimpan#

CREATE VIEW menyimpan teks sebuah SELECT di bawah satu nama, dan nama itu kemudian dirujuk seolah-olah menjadi tabel. View yang paling berguna adalah yang merangkum join dan syarat yang selalu dipakai berulang, misalnya daftar peminjaman yang masih berjalan. Query berikut menggabungkan tabel peminjaman, anggota, dan buku, kemudian menyaring baris yang kolom tanggal_kembalinya masih NULL, lalu menyimpannya dengan nama peminjaman_aktif.

sql View peminjaman aktif dari tiga tabel
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT, tanggal_kembali TEXT);
INSERT INTO buku VALUES
  (1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
  (4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
  (1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
  (4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
  (1, 1, 1, '2026-03-02', NULL), (2, 3, 2, '2026-03-04', NULL),
  (3, 1, 3, '2026-03-06', '2026-03-13'), (4, 99, 4, '2026-03-09', NULL),
  (5, 5, 5, '2026-03-11', '2026-03-18');
CREATE VIEW peminjaman_aktif AS
SELECT peminjaman.id AS id_pinjam, anggota.nama, buku.judul, peminjaman.tanggal_pinjam
FROM peminjaman
  JOIN anggota ON anggota.id = peminjaman.id_anggota
  JOIN buku ON buku.id = peminjaman.id_buku
WHERE peminjaman.tanggal_kembali IS NULL;

SELECT * FROM peminjaman_aktif;
text Keluaran
1|Ali|Dasar Algoritma|2026-03-02
2|Budi|Kode dan Sandi|2026-03-04

Keluaran memuat dua baris karena lima peminjaman pada data contoh hanya dua yang belum dikembalikan, sedangkan baris dengan id_buku 99 hilang karena tidak menemukan pasangan buku. Penting dipahami bahwa view tidak menyimpan baris hasil tersebut. SQLite hanya menyimpan teks query-nya, dan setiap kali peminjaman_aktif dirujuk, query yang tersimpan dijalankan ulang terhadap data terkini. Karena itu pembaruan pada tabel dasar langsung terlihat melalui view tanpa langkah penyegaran apa pun. Alias kolom seperti id_pinjam pada definisi juga menjadi nama kolom tampilan, dan index pada tabel dasar tetap dipakai oleh perencana query, sehingga SELECT melalui view sama cepatnya dengan query panjang aslinya.

Memeriksa dan menyusun view#

Definisi view tersimpan pada katalog internal sqlite_schema bersama objek lainnya, dengan kolom type berisi teks view. Query terhadap katalog ini berguna untuk meninjau view apa saja yang sudah ada pada satu basis data. View juga dapat disusun di atas view lain, sehingga lapisan yang menggambarkan data mentah dapat dipisahkan dari lapisan yang siap dipakai laporan. Blok berikut memeriksa daftar view yang baru dibuat, kemudian memakai view yang sama sebagai sumber agregasi seolah-olah ia tabel biasa.

sql Daftar view dan agregasi di atas view
CREATE TABLE anggota (id INTEGER PRIMARY KEY, nama TEXT);
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE TABLE peminjaman (id INTEGER PRIMARY KEY, id_buku INTEGER, id_anggota INTEGER, tanggal_pinjam TEXT, tanggal_kembali TEXT);
INSERT INTO buku VALUES
  (1, 'Dasar Algoritma'), (2, 'Peta Langit'), (3, 'Kode dan Sandi'),
  (4, 'Sejarah Kertas'), (5, 'Jejak Angin'), (6, 'Arsip Suara');
INSERT INTO anggota VALUES
  (1, 'Ali'), (2, 'Budi'), (3, 'Citra'),
  (4, 'Dewi'), (5, 'Eka'), (6, 'Farhan');
INSERT INTO peminjaman VALUES
  (1, 1, 1, '2026-03-02', NULL), (2, 3, 2, '2026-03-04', NULL),
  (3, 1, 3, '2026-03-06', '2026-03-13'), (4, 99, 4, '2026-03-09', NULL),
  (5, 5, 5, '2026-03-11', '2026-03-18');
CREATE VIEW peminjaman_aktif AS
SELECT peminjaman.id AS id_pinjam, anggota.nama, buku.judul, peminjaman.tanggal_pinjam
FROM peminjaman
  JOIN anggota ON anggota.id = peminjaman.id_anggota
  JOIN buku ON buku.id = peminjaman.id_buku
WHERE peminjaman.tanggal_kembali IS NULL;

SELECT name, type FROM sqlite_schema WHERE type = 'view';
SELECT nama, COUNT(*) AS banyak FROM peminjaman_aktif GROUP BY nama ORDER BY nama;
text Keluaran
peminjaman_aktif|view
Ali|1
Budi|1

Baris pertama keluaran menegaskan bahwa hanya ada satu view dengan nama yang baru dideklarasikan, sedangkan dua baris berikutnya menunjukkan query GROUP BY berjalan normal di atas view. Syarat WHERE tambahan dari query luar diterapkan di atas hasil view, sehingga view dapat dibaca sebagai tabel virtual yang isinya selalu segar. Bagian WHERE pada definisi view juga boleh dirantai, misalnya view yang menyaring kategori tertentu lalu dibungkus view kedua yang menghitung jumlahnya.

Batas pembaruan pada view#

SQLite menetapkan seluruh view sebagai objek yang hanya dapat dibaca, dan dokumentasinya menyatakan pernyataan DELETE, INSERT, serta UPDATE tidak boleh dijalankan terhadap view. Penolakan itu berlaku bahkan pada view sederhana yang kolomnya berasal dari satu tabel tanpa join. Blok berikut memperagakan dua percobaan pembaruan, yaitu pada view satu tabel bernama stok_buku dan pada view satu kolom bernama judul_saja, dan keduanya ditolak dengan pesan yang sama bentuknya.

sql Percobaan UPDATE pada dua view sederhana
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT, jumlah INTEGER);
INSERT INTO buku VALUES (1, 'Dasar Algoritma', 3);
CREATE VIEW stok_buku AS SELECT id, judul, jumlah FROM buku;
CREATE VIEW judul_saja AS SELECT judul FROM buku;

UPDATE stok_buku SET jumlah = 4 WHERE id = 1;
UPDATE judul_saja SET judul = 'Algoritma Dasar' WHERE id = 1;
text Keluaran
Parse error near line 6: cannot modify stok_buku because it is a view
Parse error near line 7: cannot modify judul_saja because it is a view

Pesan error menyebut nama view-nya secara eksplisit, sehingga penyebabnya mudah dilacak. Perilaku ini berbeda dari beberapa basis data lain yang memperbarui view sederhana secara otomatis, sedangkan SQLite menuntut saluran pembaruan yang didefinisikan sendiri. Tanpa saluran itu, SQLite tidak menebak tabel mana yang dimaksud dan menolak seluruh perintahnya, termasuk pada view berjoin yang tabel dasarnya memang lebih dari satu.

INSTEAD OF trigger sebagai jalan keluar#

Trigger INSTEAD OF dipasang pada sebuah view dan mengalihkan perintah pembaruan ke definisi yang ditulis sendiri, sehingga view menjadi dapat ditulis tanpa kehilangan sifat aslinya. Ketika UPDATE dijalankan terhadap view, SQLite tidak menyentuh view sama sekali, melainkan mengeksekusi isi trigger tersebut. Blok berikut membuat view stok beserta trigger pembaruannya, lalu menjalankan UPDATE melalui view dan memverifikasi bahwa tabel dasar ikut berubah. Perintah yang dialihkan menyesuaikan kata pada definisinya, sehingga view yang menerima INSERT maupun DELETE memerlukan trigger terpisah untuk masing-masing perintah.

sql View yang dapat diperbarui lewat INSTEAD OF trigger
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT, jumlah INTEGER);
INSERT INTO buku VALUES (1, 'Dasar Algoritma', 3), (2, 'Peta Langit', 2);
CREATE VIEW stok_buku AS SELECT id, judul, jumlah FROM buku;
CREATE TRIGGER stok_buku_ubah
INSTEAD OF UPDATE ON stok_buku
BEGIN
  UPDATE buku SET jumlah = NEW.jumlah WHERE id = NEW.id;
END;

UPDATE stok_buku SET jumlah = 4 WHERE id = 1;
SELECT * FROM stok_buku;
text Keluaran
1|Dasar Algoritma|4
2|Peta Langit|2

UPDATE yang semula ditolak kini berhasil karena trigger mengalihkannya ke UPDATE pada tabel buku, dan SELECT berikutnya memperlihatkan jumlah buku pertama menjadi 4. Struktur NEW pada isi trigger merujuk baris baru yang diteruskan dari perintah pembaruan. Pola ini cukup ditulis sekali, dan pembahasan lengkapnya tersedia pada topik Trigger yang membahas AFTER dan INSTEAD OF secara berdampingan. Pola yang sama berlaku pada view berjoin, dengan syarat isi trigger menentukan tabel dasar mana yang menjadi sasaran perubahan.

DROP VIEW#

DROP VIEW menghapus definisi view dari basis data tanpa menyinggung tabel dasarnya, sehingga datanya tetap utuh. Setelah view dihapus, setiap query yang masih merujuknya gagal saat dijalankan, sebagaimana diperagakan blok berikut yang menghapus buku_ringkas lalu memilih dari view yang sudah tidak ada. Penghapusan hanya menyasar definisi querynya, sehingga operasi ini cepat dan tidak menyentuh data sama sekali.

sql Menghapus view lalu merujuknya kembali
CREATE TABLE buku (id INTEGER PRIMARY KEY, judul TEXT);
CREATE VIEW buku_ringkas AS SELECT judul FROM buku;

DROP VIEW buku_ringkas;
SELECT * FROM buku_ringkas;
text Keluaran
Parse error near line 5: no such table: buku_ringkas

Pesan error berbunyi no such table karena view memang dirujuk lewat mekanisme penamaan yang sama dengan tabel, padahal objek yang hilang adalah view. Untuk skrip yang boleh dijalankan berulang, bentuk DROP VIEW IF EXISTS menghapus view hanya bila ada dan diam tanpa error bila tidak ada. Kebiasaan yang sehat adalah menghapus view yang tidak terpakai agar daftar objek pada basis data tetap mencerminkan yang benar-benar dirujuk. View yang dihapus tidak meninggalkan jejak pada tabel dasar, sehingga pemulihannya cukup dengan menjalankan ulang CREATE VIEW yang lama. Simpan definisi view penting pada berkas skrip inisialisasi agar pembangunan ulangnya tidak bergantung pada ingatan.

Kesalahan umum#

Mengira view menyimpan salinan data. View yang dibuat hari ini tidak membekukan isi tabelnya, karena SQLite menjalankan ulang query tersimpan setiap kali view dirujuk. Kesimpulan praktisnya adalah view cocok untuk merangkum query, tetapi tidak cocok untuk mengarsipkan kondisi data pada suatu saat tertentu. Kalau arsip kondisi tertentu memang diperlukan, buat tabel yang diisi oleh query dan jangan mengandalkan view.

Menghapus atau mengubah nama tabel yang dirujuk oleh view. Pembuatan view tidak memeriksa masa depan, sehingga DROP TABLE pada tabel dasar tetap berhasil, sedangkan error baru muncul ketika view dirujuk kembali. Jalankan ulang query view setelah setiap perubahan schema untuk memastikan rantai rujukannya masih lengkap.

Menulis ulang join yang panjang di setiap query padahal polanya tetap. Kebiasaan ini membuat perbedaan kecil antarquery sulit ditemukan, misalnya syarat tanggal yang berbeda satu karakter. Definisikan view untuk pola yang berulang, lalu tambahkan penyaringan khusus pada query yang memanggilnya. Pendekatan ini juga menjaga antarlaporan konsisten karena join yang sama tidak diketik ulang dengan variasi kecil.

Ringkasan#

  • CREATE VIEW menyimpan teks SELECT dengan satu nama, dan view dirujuk seperti tabel karena querynya dijalankan ulang terhadap data terkini.
  • Definisi view tercatat pada sqlite_schema dengan kolom type bernilai view, dan view boleh disusun di atas view lain.
  • Seluruh view pada SQLite hanya dapat dibaca, sehingga UPDATE maupun INSERT ke view ditolak, dan trigger INSTEAD OF menjadi saluran pembaruannya.
  • DROP VIEW menghapus definisi view tanpa menyentuh tabel dasar, dan bentuk DROP VIEW IF EXISTS aman untuk skrip berulang.

Referensi#