Khi xây dựng ứng dụng Oracle APEX, developer thường bắt đầu rất nhanh bằng cách viết SQL trực tiếp
trong region source: Classic Report, Interactive Report, Cards, LOV, Chart hoặc Page Process.
Cách này tiện ở giai đoạn đầu, nhưng nếu ứng dụng lớn dần, cùng một logic SQL có thể bị copy sang nhiều page,
nhiều region và nhiều component khác nhau.
Lúc đó, việc chỉnh sửa trở nên khó khăn. Một thay đổi nhỏ trong business logic có thể buộc bạn phải tìm và sửa
ở rất nhiều nơi. Nếu bỏ sót một region, dữ liệu hiển thị sẽ không còn nhất quán. Đây là lý do database views
rất quan trọng trong phát triển Oracle APEX.
Bài viết này tập trung vào vai trò của database views trong quá trình phát triển ứng dụng Oracle APEX.
Dù ngày nay có nhiều công nghệ mới như AI, REST APIs, JSON, Vector Search hay Agent,
những nền tảng cơ bản như database views vẫn là một phần rất quan trọng để xây ứng dụng APEX sạch,
dễ bảo trì, nhất quán và an toàn hơn.
Database View là gì?
Database view là một object trong Oracle Database, đại diện cho một câu SQL được đặt tên.
Thay vì viết lại cùng một câu query ở nhiều nơi, bạn tạo một view, rồi các page APEX chỉ cần query từ view đó.
Ví dụ, thay vì nhiều report cùng viết:
select c.customer_id,
c.customer_name,
c.email,
c.status,
count(o.order_id) as total_orders,
sum(o.order_total) as total_amount
from customers c
left join orders o
on o.customer_id = c.customer_id
group by c.customer_id,
c.customer_name,
c.email,
c.status
Bạn có thể tạo view:
create or replace view v_customer_summary as
select c.customer_id,
c.customer_name,
c.email,
c.status,
count(o.order_id) as total_orders,
sum(o.order_total) as total_amount
from customers c
left join orders o
on o.customer_id = c.customer_id
group by c.customer_id,
c.customer_name,
c.email,
c.status;
Sau đó trong APEX, report chỉ cần:
select *
from v_customer_summary
where status = 'ACTIVE';
SQL trong APEX trở nên ngắn hơn, dễ đọc hơn và logic tổng hợp được quản lý ở một nơi.
Lược đồ tổng quan: Table, View và APEX Page
Database View Architecture trong Oracle APEX
Tables
Dữ liệu gốc: customers, orders, products, users, logs...
→
Views
Chuẩn hóa query, join, filter, calculated columns và security rules.
→
APEX Pages
Reports, Cards, Charts, LOVs và Forms sử dụng source đơn giản hơn.
View đóng vai trò như lớp trung gian giữa bảng dữ liệu gốc và giao diện APEX,
giúp giảm lặp SQL, tăng tính nhất quán và dễ kiểm soát logic hiển thị.
View giúp tái sử dụng SQL
Trong APEX, cùng một dữ liệu có thể được dùng ở nhiều nơi: report, chart, card, LOV, export, email template
hoặc REST API. Nếu mỗi nơi tự viết một câu SQL riêng, logic rất dễ bị lệch nhau.
Ví dụ, bạn có một logic xác định “đơn hàng đang mở”:
status in ('NEW', 'PROCESSING', 'WAITING_PAYMENT')
Nếu logic này được copy vào 10 region khác nhau, sau này khi thêm trạng thái mới như ON_HOLD,
bạn phải sửa cả 10 nơi. Nếu quên một nơi, người dùng sẽ thấy số liệu không khớp.
Cách tốt hơn là tạo view:
create or replace view v_open_orders as
select *
from orders
where status in ('NEW', 'PROCESSING', 'WAITING_PAYMENT', 'ON_HOLD');
Sau đó mọi region cần danh sách đơn hàng đang mở chỉ query từ v_open_orders.
View giúp chuẩn hóa business logic hiển thị
Không phải business logic nào cũng nên nằm trong view. Các logic transaction quan trọng vẫn nên nằm trong package PL/SQL.
Nhưng với logic phục vụ hiển thị, tổng hợp, phân loại hoặc tính cột phụ, view là nơi rất phù hợp.
Ví dụ:
- Tính số ngày quá hạn.
- Gộp họ tên từ nhiều cột.
- Hiển thị trạng thái thân thiện hơn.
- Tính tổng số đơn hàng của khách hàng.
- Join bảng lookup để lấy tên thay vì ID.
- Lọc dữ liệu chỉ lấy bản ghi active.
Ví dụ view thêm cột tính toán:
create or replace view v_task_list as
select t.task_id,
t.task_name,
t.assigned_to,
t.status,
t.due_date,
case
when t.status = 'DONE' then 'Completed'
when t.due_date < trunc(sysdate) then 'Overdue'
else 'Open'
end as display_status,
trunc(sysdate) - t.due_date as days_overdue
from project_tasks t;
APEX page chỉ cần dùng display_status và days_overdue,
không cần viết lại logic này ở từng report.
View giúp bảo mật dữ liệu tốt hơn
Một lý do quan trọng để dùng view là bảo mật. Không phải lúc nào APEX page cũng nên query trực tiếp từ table gốc.
Table có thể chứa nhiều cột nhạy cảm hơn những gì UI cần hiển thị.
Ví dụ bảng employees có thể có:
- employee_id
- employee_name
- email
- salary
- national_id
- bank_account
- status
Nhưng report nhân sự thông thường chỉ cần tên, email và trạng thái. Bạn có thể tạo view:
create or replace view v_employee_directory as
select employee_id,
employee_name,
email,
status
from employees
where status = 'ACTIVE';
APEX page dùng view này sẽ không vô tình expose các cột nhạy cảm như lương, số định danh hoặc tài khoản ngân hàng.
View không thay thế hoàn toàn authorization, nhưng nó là một lớp rất hữu ích để giảm bề mặt rủi ro.
Bạn vẫn nên kết hợp với Authorization Scheme, kiểm tra quyền ở server-side và các chính sách bảo mật phù hợp.
View giúp APEX Page Source gọn hơn
Một region source quá dài thường khó đọc và khó maintain trong Page Designer.
Nếu câu SQL có nhiều join, nhiều calculated columns, nhiều CASE expression và nhiều filter lặp lại,
bạn nên cân nhắc đưa phần đó vào view.
Khi page source ngắn hơn, developer mở Page Designer sẽ hiểu nhanh hơn region đó đang làm gì.
Ví dụ:
select *
from v_invoice_dashboard
where invoice_month = :P10_MONTH
dễ đọc hơn nhiều so với một câu SQL dài hàng trăm dòng trong region source.
View giúp nhiều component dùng cùng một nguồn dữ liệu
Một view có thể phục vụ nhiều component APEX:
- Interactive Report.
- Classic Report.
- Cards.
- Charts.
- LOV.
- REST-enabled SQL hoặc ORDS API.
- Email template hoặc automation.
Ví dụ, v_sales_summary có thể dùng cho chart doanh thu, report chi tiết,
card KPI trên dashboard và automation gửi báo cáo tuần.
Khi tất cả component dùng cùng một view, bạn giảm nguy cơ mỗi nơi tính số liệu theo một cách khác nhau.
View giúp tách UI khỏi cấu trúc bảng thật
Cấu trúc table trong database có thể thay đổi theo thời gian. Nếu APEX page query trực tiếp table ở nhiều nơi,
mỗi thay đổi table có thể làm hỏng nhiều region.
View có thể đóng vai trò như một lớp ổn định giữa UI và schema thật.
Nếu table bên dưới thay đổi, bạn có thể chỉnh view để giữ nguyên interface cho APEX page.
Ví dụ, ban đầu APEX page dùng cột customer_name. Sau này bạn tách thành
first_name và last_name. View có thể tiếp tục expose:
first_name || ' ' || last_name as customer_name
Nhờ đó, APEX page không cần sửa ngay ở tất cả nơi đang dùng customer_name.
View có thể hỗ trợ performance, nhưng không phải phép màu
Dùng view không tự động làm SQL nhanh hơn. View chủ yếu giúp tổ chức logic tốt hơn.
Performance vẫn phụ thuộc vào query plan, index, statistics, filter, join và volume dữ liệu.
Tuy nhiên, view giúp bạn tập trung tối ưu ở một nơi. Nếu nhiều page dùng cùng một view,
bạn có thể xem execution plan của view, thêm index phù hợp cho table bên dưới,
hoặc điều chỉnh query trong view để cải thiện cho nhiều component cùng lúc.
Với các case tổng hợp dữ liệu nặng, bạn có thể cân nhắc materialized view,
summary table hoặc automation/job cập nhật dữ liệu tổng hợp.
View thường, materialized view và table: nên chọn gì?
Bạn có thể dùng quy tắc đơn giản:
- View thường: phù hợp cho query logic, join, filter và calculated columns cần realtime.
- Materialized View: phù hợp cho dữ liệu tổng hợp nặng, không cần realtime tuyệt đối.
- Table: phù hợp cho dữ liệu gốc cần insert/update/delete trực tiếp.
Nếu report dashboard tính toán nặng và người dùng mở thường xuyên, materialized view có thể tốt hơn view thường.
Nhưng với phần lớn report/form thông thường trong APEX, view thường đã đủ hữu ích.
Đặt tên view như thế nào?
Đặt tên view rõ ràng giúp project dễ hiểu hơn. Một số convention thường dùng:
v_customer_summary: view tổng hợp khách hàng.
v_open_orders: view danh sách đơn hàng đang mở.
v_task_list: view phục vụ danh sách task.
v_invoice_dashboard: view phục vụ dashboard hóa đơn.
v_employee_directory: view danh bạ nhân viên.
Nên đặt tên theo mục đích sử dụng hoặc business concept, không nên đặt tên quá chung chung như
v_data, v_report hoặc v_test.
Khi nào không nên dùng view?
View rất hữu ích, nhưng không phải mọi thứ đều nên đưa vào view.
Không nên dùng view để:
- Che giấu business logic transaction phức tạp.
- Thay thế package PL/SQL cho xử lý nghiệp vụ quan trọng.
- Nhồi quá nhiều logic khiến view khó hiểu hơn cả query gốc.
- Tạo quá nhiều lớp view chồng view mà không kiểm soát performance.
- Làm nơi xử lý quyền phức tạp mà không có thiết kế bảo mật rõ ràng.
View nên giúp ứng dụng rõ ràng hơn. Nếu view làm logic khó lần theo hơn, bạn cần xem lại thiết kế.
Pattern tốt: View cho đọc, Package cho ghi
Một pattern rất thực tế trong APEX là:
- Dùng view cho các màn hình đọc dữ liệu: report, card, chart, LOV.
- Dùng table hoặc form chuẩn cho dữ liệu đơn giản.
- Dùng package PL/SQL cho các thao tác ghi dữ liệu quan trọng: submit, approve, cancel, close.
Ví dụ:
-- Report source
select *
from v_expense_report_list
where employee_id = :P10_EMPLOYEE_ID;
-- Process submit
begin
expense_pkg.submit_expense(
p_expense_id => :P20_EXPENSE_ID,
p_user => :APP_USER
);
end;
Cách này giúp phần đọc dữ liệu gọn và nhất quán, còn phần ghi dữ liệu được kiểm soát trong package.
Best practice khi dùng views trong APEX
Một số nguyên tắc nên áp dụng:
- Đưa các query lặp lại vào view.
- Không expose cột nhạy cảm nếu UI không cần.
- Đặt tên view rõ theo business concept.
- Comment view và column nếu view quan trọng.
- Không tạo quá nhiều tầng view chồng nhau nếu không cần.
- Kiểm tra execution plan cho view dùng nhiều.
- Dùng bind variables ở APEX region để filter thêm thay vì hard-code quá nhiều trường hợp.
- Dùng package PL/SQL cho logic ghi dữ liệu, không nhồi vào view.
Ví dụ hoàn chỉnh: View cho trang Blog
Giả sử bạn có bảng blog như blog_posts và blog_categories.
Bạn có thể tạo một view phục vụ danh sách bài viết:
create or replace view v_blog_post_list as
select p.id,
p.title,
p.slug,
p.summary,
p.published_at,
p.status,
c.name as category_name,
c.slug as category_slug
from blog_posts p
join blog_categories c
on c.id = p.category_id
where p.status = 'PUBLISHED';
Sau đó Blog List trong APEX chỉ cần:
select title,
slug,
summary,
published_at,
category_name
from v_blog_post_list
order by published_at desc;
Nếu sau này bạn muốn thêm filter, thêm category, đổi cách join hoặc thêm cột hiển thị,
bạn có thể chỉnh view thay vì sửa nhiều region.
Kết luận
Database views là một công cụ rất cơ bản nhưng cực kỳ quan trọng trong Oracle APEX.
View giúp tái sử dụng SQL, giảm lặp logic, bảo vệ dữ liệu nhạy cảm, chuẩn hóa cách hiển thị
và giữ Page Designer gọn hơn.
Dùng view không có nghĩa là bỏ qua performance, authorization hoặc PL/SQL packages.
Ngược lại, view nên là một phần của kiến trúc rõ ràng: view cho dữ liệu đọc và hiển thị,
package cho nghiệp vụ ghi dữ liệu, authorization cho quyền truy cập.
Khi làm đúng những điều cơ bản này, ứng dụng APEX sẽ dễ bảo trì hơn, ít lỗi nhất quán hơn
và chuyên nghiệp hơn khi phát triển lâu dài.