Laporan penjualan per kategori, daftar harga produk, rekap transaksi per pelanggan — query-query seperti ini ditulis berulang kali oleh analis, aplikasi, dan anggota tim yang berbeda. Setiap penyalinan query membuka peluang perubahan diam-diam: satu salinan memakai INNER JOIN, salinan lain lupa filter kategori, dan angka laporan tidak lagi cocok antar bagian perusahaan. VIEW menyelesaikan masalah itu dengan cara yang sederhana namun mengubah cara kita bekerja: beri nama pada sebuah query, simpan query itu di database, lalu perlakukan hasilnya seperti tabel. Chapter ini membahas cara membuat view, membuktikan bahwa view tidak menyalin data, dan membungkus query join-plus-agregat menjadi laporan siap pakai.

Tabel Latihan: produk, pelanggan, penjualan #

Domain latihan untuk seluruh section ini adalah tiga tabel Toko Maju Jaya: produk (katalog dengan harga dan stok), pelanggan (lima pembeli tetap), dan penjualan (sepuluh transaksi sepanjang Januari–Februari 2026). Perhatikan produk Kopi Lampung: stoknya nol dan belum pernah terjual — produk itu akan berperan kecil tapi penting di paruh akhir chapter:

sql buat-tabel.sql
-- Domain latihan section View dan Materialized View:
-- katalog produk, pelanggan, dan transaksi Toko Maju Jaya.
CREATE TABLE produk (
    id       integer PRIMARY KEY,
    nama     text NOT NULL,
    kategori text NOT NULL,
    harga    numeric(10,2) NOT NULL,
    stok     integer NOT NULL
);

CREATE TABLE pelanggan (
    id   integer PRIMARY KEY,
    nama text NOT NULL,
    kota text NOT NULL
);

CREATE TABLE penjualan (
    id           integer PRIMARY KEY,
    tanggal      date NOT NULL,
    produk_id    integer NOT NULL REFERENCES produk(id),
    pelanggan_id integer NOT NULL REFERENCES pelanggan(id),
    jumlah       integer NOT NULL
);

INSERT INTO produk (id, nama, kategori, harga, stok) VALUES
    (1, 'Kopi Gayo',    'Kopi', 85000.00,  40),
    (2, 'Kopi Toraja',  'Kopi', 90000.00,  25),
    (3, 'Teh Melati',   'Teh',  35000.00, 100),
    (4, 'Teh Hijau',    'Teh',  40000.00,  60),
    (5, 'Gula Merah',   'Gula', 15000.00, 200),
    (6, 'Gula Putih',   'Gula', 16000.00, 150),
    (7, 'Kopi Lampung', 'Kopi', 78000.00,   0);

INSERT INTO pelanggan (id, nama, kota) VALUES
    (1, 'Budi Santoso', 'Jakarta'),
    (2, 'Siti Aminah',  'Bandung'),
    (3, 'Andi Wijaya',  'Surabaya'),
    (4, 'Dewi Lestari', 'Yogyakarta'),
    (5, 'Rina Marlina', 'Medan');

INSERT INTO penjualan (id, tanggal, produk_id, pelanggan_id, jumlah) VALUES
    ( 1, DATE '2026-01-05', 1, 1, 10),
    ( 2, DATE '2026-01-08', 3, 2, 25),
    ( 3, DATE '2026-01-12', 5, 3, 40),
    ( 4, DATE '2026-01-15', 2, 1,  8),
    ( 5, DATE '2026-01-20', 4, 4, 15),
    ( 6, DATE '2026-01-22', 1, 2, 12),
    ( 7, DATE '2026-02-02', 3, 5, 20),
    ( 8, DATE '2026-02-05', 6, 3, 30),
    ( 9, DATE '2026-02-10', 2, 4,  6),
    (10, DATE '2026-02-14', 4, 1, 18);

SELECT id, nama, kategori, harga, stok FROM produk ORDER BY id;
SELECT id, nama, kota FROM pelanggan ORDER BY id;
SELECT id, tanggal, produk_id, pelanggan_id, jumlah FROM penjualan ORDER BY id;

Output yang Dihasilkan:

text
CREATE TABLE
CREATE TABLE
CREATE TABLE
INSERT 0 7
INSERT 0 5
INSERT 0 10
 id |     nama     | kategori |  harga   | stok 
----+--------------+----------+----------+------
  1 | Kopi Gayo    | Kopi     | 85000.00 |   40
  2 | Kopi Toraja  | Kopi     | 90000.00 |   25
  3 | Teh Melati   | Teh      | 35000.00 |  100
  4 | Teh Hijau    | Teh      | 40000.00 |   60
  5 | Gula Merah   | Gula     | 15000.00 |  200
  6 | Gula Putih   | Gula     | 16000.00 |  150
  7 | Kopi Lampung | Kopi     | 78000.00 |    0
(7 rows)

 id |     nama     |    kota    
----+--------------+------------
  1 | Budi Santoso | Jakarta
  2 | Siti Aminah  | Bandung
  3 | Andi Wijaya  | Surabaya
  4 | Dewi Lestari | Yogyakarta
  5 | Rina Marlina | Medan
(5 rows)

 id |  tanggal   | produk_id | pelanggan_id | jumlah 
----+------------+-----------+--------------+--------
  1 | 2026-01-05 |         1 |            1 |     10
  2 | 2026-01-08 |         3 |            2 |     25
  3 | 2026-01-12 |         5 |            3 |     40
  4 | 2026-01-15 |         2 |            1 |      8
  5 | 2026-01-20 |         4 |            4 |     15
  6 | 2026-01-22 |         1 |            2 |     12
  7 | 2026-02-02 |         3 |            5 |     20
  8 | 2026-02-05 |         6 |            3 |     30
  9 | 2026-02-10 |         2 |            4 |      6
 10 | 2026-02-14 |         4 |            1 |     18
(10 rows)

Membuat View Pertama #

Sintaks dasarnya sepenggal: CREATE VIEW nama_view AS query;. Server membaca query di balik AS, mem-parse-nya menjadi pohon query, lalu menyimpan pohon itu sebagai definisi objek bernama daftar_harga. Mulai saat itu, daftar_harga bisa dipakai di FROM seperti tabel biasa:

-- View pertama: bungkus query sederhana menjadi objek bernama.
-- CREATE VIEW hanya menyimpan query-nya; tidak ada data yang disalin.
CREATE VIEW daftar_harga AS
SELECT nama, kategori, harga
FROM produk;

-- View dipakai persis seperti tabel: SELECT biasa dengan
-- WHERE dan ORDER BY, tanpa perlu menulis ulang query aslinya.
SELECT nama, kategori, harga
FROM daftar_harga
ORDER BY harga DESC, nama;

SELECT nama, harga
FROM daftar_harga
WHERE kategori = 'Kopi'
ORDER BY harga DESC;

Output yang Dihasilkan:

text
CREATE VIEW
     nama     | kategori |  harga   
--------------+----------+----------
 Kopi Toraja  | Kopi     | 90000.00
 Kopi Gayo    | Kopi     | 85000.00
 Kopi Lampung | Kopi     | 78000.00
 Teh Hijau    | Teh      | 40000.00
 Teh Melati   | Teh      | 35000.00
 Gula Putih   | Gula     | 16000.00
 Gula Merah   | Gula     | 15000.00
(7 rows)

     nama     |  harga   
--------------+----------
 Kopi Toraja  | 90000.00
 Kopi Gayo    | 85000.00
 Kopi Lampung | 78000.00
(3 rows)

Mari kita bedah isi file tersebut:

  1. CREATE VIEW daftar_harga AS SELECT ... — query tiga kolom dari produk kini punya nama. Tidak ada baris data yang berpindah; yang disimpan hanyalah definisi query.
  2. Query pertama (ORDER BY harga DESC, nama) — membaca seluruh isi view lalu mengurutkannya. Kolom harga diurutkan menurun, dengan nama sebagai pemecah seri.
  3. Query kedua (WHERE kategori = 'Kopi') — membuktikan view menerima filter seperti tabel: PostgreSQL menjalankan query tersimpan, lalu menerapkan WHERE dan ORDER BY dari query luar di atasnya.

Perhatikan bahwa nama kolom view diambil dari daftar SELECT query aslinya: nama, kategori, harga. Karena itu alias pada kolom hasil agregat (yang akan kita pakai sebentar lagi) berfungsi ganda — merapikan tampilan sekaligus menamai kolom view.

View Menyimpan Query, Bukan Data #

Kesalahpahaman paling umum tentang view adalah menganggapnya salinan data yang harus “disinkronkan”. Buktinya bisa dilihat dari dua arah. Pertama, dari catalog pg_class — tabel sistem yang mencatat semua relasi — kolom relkind membedakan jenisnya: r untuk tabel biasa (row), v untuk view. Kedua, dari perilaku: ubah satu baris di tabel dasar, dan view memperlihatkan harga baru seketika tanpa proses apa pun:

-- Bukti bahwa view menyimpan query, bukan salinan data:
-- pg_class mencatat jenis relasi -- 'r' = tabel biasa, 'v' = view.
SELECT relname, relkind
FROM pg_class
WHERE relname IN ('produk', 'daftar_harga')
ORDER BY relname;

-- Ubah satu harga di tabel dasar ...
UPDATE produk SET harga = 88000.00 WHERE nama = 'Kopi Gayo';

-- ... dan view langsung memperlihatkan harga baru:
-- tidak ada proses "sinkronisasi" karena memang tidak ada data duplikat.
SELECT nama, harga
FROM daftar_harga
WHERE nama = 'Kopi Gayo';

-- Kembalikan harga semula agar contoh-contoh berikutnya konsisten.
UPDATE produk SET harga = 85000.00 WHERE nama = 'Kopi Gayo';

Output yang Dihasilkan:

text
   relname    | relkind 
--------------+---------
 daftar_harga | v
 produk       | r
(2 rows)

UPDATE 1
   nama    |  harga   
-----------+----------
 Kopi Gayo | 88000.00
(1 row)

UPDATE 1

Urutan kejadiannya menegaskan mekanismenya: produk tercatat sebagai r (tabel), daftar_harga sebagai v (view). UPDATE menyentuh tabel produk saja — view tidak disentuh dan tidak bisa disentuh, sebab tidak ada datanya. Ketika query berikutnya membaca daftar_harga, PostgreSQL menjalankan ulang query tersimpan di titik itu, sehingga harga 88000.00 muncul seketika. Tidak ada tabel bayangan, tidak ada job sinkronisasi; yang ada hanyalah query yang dievaluasi setiap kali dibaca.

Konsekuensi dari mekanisme ini perlu dipahami sejak awal: view selalu segar (tidak pernah basi), tetapi biaya komputasinya dibayar setiap kali view dibaca. Untuk laporan berat yang dibaca jauh lebih sering daripada dihitung, PostgreSQL menyediakan varian lain — materialized view — yang membekukan hasil; varian itu dibahas di chapter akhir section ini.

View untuk Laporan: Join, Agregat, GROUP BY #

Kekuatan view baru terasa ketika query yang dibungkus bukan SELECT tiga kolom, melainkan laporan utuh dengan join dan agregat. Kita bungkus rekap penjualan per kategori — total transaksi, total unit, dan total nilai rupiah — menjadi ringkasan_penjualan:

-- View untuk laporan: join + agregat + GROUP BY, dibungkus menjadi
-- satu objek bernama ringkasan_penjualan.
CREATE VIEW ringkasan_penjualan AS
SELECT pr.kategori,
       count(*)                 AS transaksi,
       sum(pe.jumlah)           AS total_unit,
       sum(pe.jumlah * pr.harga) AS total_nilai
FROM penjualan pe
JOIN produk pr ON pr.id = pe.produk_id
GROUP BY pr.kategori;

-- Laporan per kategori kini satu baris query, bukan query 6 baris.
SELECT kategori, transaksi, total_unit, total_nilai
FROM ringkasan_penjualan
ORDER BY kategori;

-- View juga bisa disaring dan diurutkan lebih lanjut
-- seperti tabel biasa.
SELECT kategori, total_nilai
FROM ringkasan_penjualan
WHERE total_nilai >= 1500000
ORDER BY total_nilai DESC;

Output yang Dihasilkan:

text
CREATE VIEW
 kategori | transaksi | total_unit | total_nilai 
----------+-----------+------------+-------------
 Gula     |         2 |         70 |  1080000.00
 Kopi     |         4 |         36 |  3130000.00
 Teh      |         4 |         78 |  2895000.00
(3 rows)

 kategori | total_nilai 
----------+-------------
 Kopi     |  3130000.00
 Teh      |  2895000.00
(2 rows)

Mari kita bedah definisi view tersebut baris per baris:

  1. SELECT pr.kategori, ... — alias pr (produk) dan pe (penjualan) menjaga agar kolom kategori dan harga jelas asalnya, seperti pada chapter INNER JOIN .
  2. count(*), sum(pe.jumlah), sum(pe.jumlah * pr.harga) — tiga agregat berjalan di dalam tiap kelompok GROUP BY pr.kategori, persis pola chapter GROUP BY ; alias transaksi, total_unit, total_nilai sekaligus menjadi nama kolom view.
  3. JOIN produk pr ON pr.id = pe.produk_id — join diperlukan karena penjualan hanya menyimpan produk_id; harga satuan hidup di tabel produk.
  4. Query pemakai (SELECT ... FROM ringkasan_penjualan) — enam baris logika laporan lenyap; pemakai cukup membaca kategori dan angkanya. Query kedua menambah WHERE total_nilai >= 1500000 untuk memfilter hasil view, layaknya filter pada tabel.

Dua detail hasil layak dicermati. Pertama, kategori Kopi unggul dengan nilai 3130000.00 dari 4 transaksi, sementara Gula hanya menyumbang 1080000.00 dari 2 transaksi. Kedua, Kopi Lampung tidak muncul di mana pun — view ini memakai INNER JOIN, dan produk tanpa transaksi tersaring di join, bukan di agregat. Ini perilaku query aslinya yang diwariskan apa adanya ke view: view tidak menambah dan tidak mengurangi semantik query yang dibungkusnya.

Memeriksa Definisi View #

Setelah beberapa view tercipta, dua alat bawaan membantu memeriksanya. Meta-command \d+ nama_view membedah satu view sampai ke tipe kolom dan definisi lengkapnya. Catalog view pg_views mendaftar semua view dalam database — tempat paling tepat untuk menjawab “view apa saja yang sudah ada di sini?”:

-- Dua cara memeriksa view yang sudah dibuat:
-- \d+ membedah satu view sampai ke definisi dan tipe kolomnya.
\d+ ringkasan_penjualan

-- pg_views adalah catalog view bawaan PostgreSQL:
-- satu-satunya tempat semua view dalam database terdaftar.
SELECT schemaname, viewname, viewowner
FROM pg_views
WHERE schemaname = 'public'
ORDER BY viewname;

Output yang Dihasilkan:

text
                        View "public.ringkasan_penjualan"
   Column    |  Type   | Collation | Nullable | Default | Storage  | Description 
-------------+---------+-----------+----------+---------+----------+-------------
 kategori    | text    |           |          |         | extended | 
 transaksi   | bigint  |           |          |         | plain    | 
 total_unit  | bigint  |           |          |         | plain    | 
 total_nilai | numeric |           |          |         | main     | 
View definition:
 SELECT pr.kategori,
    count(*) AS transaksi,
    sum(pe.jumlah) AS total_unit,
    sum(pe.jumlah::numeric * pr.harga) AS total_nilai
   FROM penjualan pe
     JOIN produk pr ON pr.id = pe.produk_id
  GROUP BY pr.kategori;

 schemaname |      viewname       | viewowner 
------------+---------------------+-----------
 public     | daftar_harga        | postgres
 public     | ringkasan_penjualan | postgres
(2 rows)

Tiga hal terbaca dari hasilnya. Pertama, \d+ memperlihatkan tipe kolom hasil: count(*) menjadi bigint, sum(...) dari numeric menjadi numeric — tipe kolom view ditentukan oleh ekspresi di daftar SELECT, bukan oleh tabel dasar. Kedua, pada bagian View definition: muncul pe.jumlah::numeric * pr.harga — PostgreSQL menambahkan cast eksplisit itu sendiri saat menyimpan definisi, karena perkalian integer dengan numeric memang mengharuskan promosi jumlah ke numeric. Ketiga, pg_views mendaftar dua view milik schema public — daftar_harga dan ringkasan_penjualan — lengkap dengan pemiliknya (postgres, pengguna yang menjalankan CREATE VIEW). Filter schemaname = 'public' menyembunyikan ratusan view sistem di schema pg_catalog dan information_schema agar daftarnya hanya berisi view milik kita.

Menamai Ulang Kolom dengan Daftar Kolom #

Kadang nama kolom asli terlalu teknis untuk pemakai view — id dan harga tidak bermakna bagi staf gudang yang membaca laporan. CREATE VIEW menyediakan daftar nama kolom opsional dalam tanda kurung, ditempatkan di antara nama view dan kata kunci AS:

sql kolom-alias.sql
-- Daftar nama kolom dalam tanda kurung menimpa nama asli
-- hasil SELECT: id -> kode, nama -> nama_produk, harga -> harga_rupiah.
CREATE VIEW produk_ringkas (kode, nama_produk, harga_rupiah) AS
SELECT id, nama, harga
FROM produk;

-- Query pemakai view hanya mengenal nama kolom yang baru.
SELECT kode, nama_produk, harga_rupiah
FROM produk_ringkas
WHERE harga_rupiah >= 78000
ORDER BY harga_rupiah DESC, kode;

Output yang Dihasilkan:

text
CREATE VIEW
 kode | nama_produk  | harga_rupiah 
------+--------------+--------------
    2 | Kopi Toraja  |     90000.00
    1 | Kopi Gayo    |     85000.00
    7 | Kopi Lampung |     78000.00
(3 rows)

Pemetaannya bekerja per posisi: kolom pertama id bernama kode, kolom kedua nama menjadi nama_produk, kolom ketiga harga menjadi harga_rupiah. Setelah view tercipta, nama lama tidak lagi dikenal — query pemakai hanya boleh memakai nama baru, seperti query kedua yang menyaring harga_rupiah >= 78000. Dua aturan kecil menyertainya: daftar nama yang lebih panjang dari daftar SELECT ditolak dengan error CREATE VIEW specifies more column names than columns, sedangkan daftar yang lebih pendek diperbolehkan — kolom yang tidak dinamai tetap memakai nama aslinya. Aturan penamaan ini akan kembali penting di chapter berikutnya, karena nama kolom adalah bagian dari kontrak antara view dan semua pemakainya.

View pertama kita sudah hidup: query panjang kini punya nama, selalu segar, dan dibaca seperti tabel. Namun kebutuhan laporan berkembang — kolom baru ingin ditambahkan, nama kolom ingin dirapikan, definisi query ingin disesuaikan. Mengubah view punya aturan mainnya sendiri yang ketat, dan melanggarnya menghasilkan error yang cukup terkenal. Chapter berikutnya membahas CREATE OR REPLACE VIEW beserta batas perubahannya: Mengubah View .

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

buat-tabel.sql

Unduh berkas
sql
-- Domain latihan section View dan Materialized View:
-- katalog produk, pelanggan, dan transaksi Toko Maju Jaya.
CREATE TABLE produk (
    id       integer PRIMARY KEY,
    nama     text NOT NULL,
    kategori text NOT NULL,
    harga    numeric(10,2) NOT NULL,
    stok     integer NOT NULL
);

CREATE TABLE pelanggan (
    id   integer PRIMARY KEY,
    nama text NOT NULL,
    kota text NOT NULL
);

CREATE TABLE penjualan (
    id           integer PRIMARY KEY,
    tanggal      date NOT NULL,
    produk_id    integer NOT NULL REFERENCES produk(id),
    pelanggan_id integer NOT NULL REFERENCES pelanggan(id),
    jumlah       integer NOT NULL
);

INSERT INTO produk (id, nama, kategori, harga, stok) VALUES
    (1, 'Kopi Gayo',    'Kopi', 85000.00,  40),
    (2, 'Kopi Toraja',  'Kopi', 90000.00,  25),
    (3, 'Teh Melati',   'Teh',  35000.00, 100),
    (4, 'Teh Hijau',    'Teh',  40000.00,  60),
    (5, 'Gula Merah',   'Gula', 15000.00, 200),
    (6, 'Gula Putih',   'Gula', 16000.00, 150),
    (7, 'Kopi Lampung', 'Kopi', 78000.00,   0);

INSERT INTO pelanggan (id, nama, kota) VALUES
    (1, 'Budi Santoso', 'Jakarta'),
    (2, 'Siti Aminah',  'Bandung'),
    (3, 'Andi Wijaya',  'Surabaya'),
    (4, 'Dewi Lestari', 'Yogyakarta'),
    (5, 'Rina Marlina', 'Medan');

INSERT INTO penjualan (id, tanggal, produk_id, pelanggan_id, jumlah) VALUES
    ( 1, DATE '2026-01-05', 1, 1, 10),
    ( 2, DATE '2026-01-08', 3, 2, 25),
    ( 3, DATE '2026-01-12', 5, 3, 40),
    ( 4, DATE '2026-01-15', 2, 1,  8),
    ( 5, DATE '2026-01-20', 4, 4, 15),
    ( 6, DATE '2026-01-22', 1, 2, 12),
    ( 7, DATE '2026-02-02', 3, 5, 20),
    ( 8, DATE '2026-02-05', 6, 3, 30),
    ( 9, DATE '2026-02-10', 2, 4,  6),
    (10, DATE '2026-02-14', 4, 1, 18);

SELECT id, nama, kategori, harga, stok FROM produk ORDER BY id;
SELECT id, nama, kota FROM pelanggan ORDER BY id;
SELECT id, tanggal, produk_id, pelanggan_id, jumlah FROM penjualan ORDER BY id;

inspeksi-view.sql

Unduh berkas
sql
-- Dua cara memeriksa view yang sudah dibuat:
-- \d+ membedah satu view sampai ke definisi dan tipe kolomnya.
\d+ ringkasan_penjualan

-- pg_views adalah catalog view bawaan PostgreSQL:
-- satu-satunya tempat semua view dalam database terdaftar.
SELECT schemaname, viewname, viewowner
FROM pg_views
WHERE schemaname = 'public'
ORDER BY viewname;

kolom-alias.sql

Unduh berkas
sql
-- Daftar nama kolom dalam tanda kurung menimpa nama asli
-- hasil SELECT: id -> kode, nama -> nama_produk, harga -> harga_rupiah.
CREATE VIEW produk_ringkas (kode, nama_produk, harga_rupiah) AS
SELECT id, nama, harga
FROM produk;

-- Query pemakai view hanya mengenal nama kolom yang baru.
SELECT kode, nama_produk, harga_rupiah
FROM produk_ringkas
WHERE harga_rupiah >= 78000
ORDER BY harga_rupiah DESC, kode;

ringkasan-penjualan.sql

Unduh berkas
sql
-- View untuk laporan: join + agregat + GROUP BY, dibungkus menjadi
-- satu objek bernama ringkasan_penjualan.
CREATE VIEW ringkasan_penjualan AS
SELECT pr.kategori,
       count(*)                 AS transaksi,
       sum(pe.jumlah)           AS total_unit,
       sum(pe.jumlah * pr.harga) AS total_nilai
FROM penjualan pe
JOIN produk pr ON pr.id = pe.produk_id
GROUP BY pr.kategori;

-- Laporan per kategori kini satu baris query, bukan query 6 baris.
SELECT kategori, transaksi, total_unit, total_nilai
FROM ringkasan_penjualan
ORDER BY kategori;

-- View juga bisa disaring dan diurutkan lebih lanjut
-- seperti tabel biasa.
SELECT kategori, total_nilai
FROM ringkasan_penjualan
WHERE total_nilai >= 1500000
ORDER BY total_nilai DESC;

view-pertama.sql

Unduh berkas
sql
-- View pertama: bungkus query sederhana menjadi objek bernama.
-- CREATE VIEW hanya menyimpan query-nya; tidak ada data yang disalin.
CREATE VIEW daftar_harga AS
SELECT nama, kategori, harga
FROM produk;

-- View dipakai persis seperti tabel: SELECT biasa dengan
-- WHERE dan ORDER BY, tanpa perlu menulis ulang query aslinya.
SELECT nama, kategori, harga
FROM daftar_harga
ORDER BY harga DESC, nama;

SELECT nama, harga
FROM daftar_harga
WHERE kategori = 'Kopi'
ORDER BY harga DESC;

view-tidak-menyalin-data.sql

Unduh berkas
sql
-- Bukti bahwa view menyimpan query, bukan salinan data:
-- pg_class mencatat jenis relasi -- 'r' = tabel biasa, 'v' = view.
SELECT relname, relkind
FROM pg_class
WHERE relname IN ('produk', 'daftar_harga')
ORDER BY relname;

-- Ubah satu harga di tabel dasar ...
UPDATE produk SET harga = 88000.00 WHERE nama = 'Kopi Gayo';

-- ... dan view langsung memperlihatkan harga baru:
-- tidak ada proses "sinkronisasi" karena memang tidak ada data duplikat.
SELECT nama, harga
FROM daftar_harga
WHERE nama = 'Kopi Gayo';

-- Kembalikan harga semula agar contoh-contoh berikutnya konsisten.
UPDATE produk SET harga = 85000.00 WHERE nama = 'Kopi Gayo';