Menu

View trong SQLite: CREATE VIEW, view tạm thời và INSTEAD OF

Cách view hoạt động trong SQLite: lưu truy vấn thành bảng ảo, khi nào dùng view tạm thời, và vì sao view của SQLite mặc định chỉ đọc được.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

View là một truy vấn được lưu lại

View là một câu lệnh SELECT có tên. Sau khi tạo, bạn có thể truy vấn nó như một bảng, nhưng không có gì được lưu trữ. Mỗi lần bạn đọc từ view, SQLite chạy lại truy vấn bên dưới từ đầu.

paid_orders trông và hoạt động như một bảng. Nó có cột, bạn có thể SELECT từ nó, bạn có thể nối nó với bảng khác. Nhưng bên dưới, mọi truy vấn đều được mở rộng thành bộ lọc WHERE status = 'paid' ban đầu.

Đó là toàn bộ mô hình tư duy: view là bí danh của một truy vấn.

Vì sao view hữu ích

Lợi ích chính là đặt tên. Một truy vấn phức tạp có một cái tên ngắn, rõ nghĩa, và phần còn lại của code vẫn dễ đọc:

Không có view, mỗi nơi gọi sẽ phải tự viết GROUP BY, và bất kỳ nơi nào cũng có thể viết sai bộ lọc. Có view, phép tổng hợp chỉ được định nghĩa một lần. Nơi gọi chỉ cần lấy customer_totals rồi thêm bộ lọc nào họ cần lên trên.

View còn có thể đóng vai trò ranh giới giống như phân quyền. Nếu một truy vấn không được để lộ cột password_hash, hãy tạo một view chọn mọi cột trừ cột đó và để code ứng dụng dùng view.

Cú pháp CREATE VIEW

Dạng đầy đủ:

CREATE [TEMPORARY] VIEW [IF NOT EXISTS] view_name [(column_aliases)] AS
SELECT ...;

Vài điều đáng biết:

  • IF NOT EXISTS bỏ qua việc tạo một cách âm thầm nếu view đã tồn tại.
  • TEMPORARY (hoặc TEMP) tạo một view biến mất khi kết nối đóng lại.
  • Bí danh cột trong ngoặc đơn cho phép đổi tên các cột của view mà không đụng tới SELECT bên dưới.

View hiển thị những tên dễ hiểu hơn (item, dollars) mà không phải đổi tên cột trong bảng nguồn.

Thay thế và xóa view

SQLite không có CREATE OR REPLACE VIEW hay ALTER VIEW. Để đổi định nghĩa của một view, hãy xóa rồi tạo lại nó:

DROP VIEW IF EXISTS active_orders; là cách viết an toàn: nó không báo lỗi nếu view không tồn tại. Xóa view không bao giờ ảnh hưởng tới các bảng bên dưới; bạn chỉ xóa truy vấn đã lưu.

View tạm thời

TEMP VIEW chỉ tồn tại trong kết nối cơ sở dữ liệu hiện tại. Khi kết nối đóng, view cũng mất. Hữu ích cho những phiên phân tích nhanh mà bạn không muốn để lại định nghĩa nào:

View tạm thời còn cho phép bạn đặt tên cho một truy vấn mà không phải đưa nó vào schema, rất tiện khi đang khám phá dữ liệu.

View mặc định chỉ đọc được

Đây là cái bẫy quan trọng nhất. Bạn không thể INSERT, UPDATE hay DELETE trực tiếp qua view:

sqlite> INSERT INTO paid_orders (customer, amount) VALUES ('Eve', 50);
Runtime error: cannot modify paid_orders because it is a view

Cách khắc phục là trigger INSTEAD OF. Bạn viết một trigger chạy thay cho lệnh ghi và chuyển nó thành một thao tác thật trên bảng bên dưới:

View vẫn là view, nhưng giờ các lệnh ghi vào nó đã có chỗ để đi. Ta sẽ nói kỹ về trigger ở trang tiếp theo.

Không có materialized view: hãy tự làm

Một số cơ sở dữ liệu cho phép lưu đệm kết quả của view trên đĩa và làm mới khi cần. SQLite thì không. Mỗi lần đọc view đều chạy lại truy vấn bên dưới. Với phần lớn khối lượng công việc thì vậy là ổn: SQLite nhanh và trình lập kế hoạch truy vấn rất tốt. Với những phép tổng hợp tốn kém được truy vấn nhiều lần, hãy tạo một bảng thật và tự giữ nó đồng bộ:

Sau đó bạn làm mới bảng đệm theo lịch, hoặc gắn trigger trên orders để giữ nó luôn cập nhật. Đây là việc thủ công, nhưng cũng là lựa chọn duy nhất trong SQLite.

Liệt kê view

Siêu dữ liệu của view nằm trong sqlite_master, cùng với bảng và index:

Cột sql trả lại câu lệnh CREATE VIEW ban đầu, hữu ích khi bạn quên mất một view làm gì. Trong CLI, .schema view_name in ra cùng nội dung đó một cách gọn gàng hơn.

Khi nào nên dùng view

View đáng dùng khi:

  • Một truy vấn không đơn giản được dùng lại ở ba chỗ trở lên. Đặt tên một lần tốt hơn sao chép rồi dán.
  • Bạn muốn chỉ để lộ một tập con cột hoặc hàng đã chọn lọc cho một phần của ứng dụng.
  • Một phép tổng hợp về mặt khái niệm là một thứ duy nhất (monthly_sales, active_users) mà nơi gọi nên coi như một danh từ.

Bỏ qua view khi:

  • Truy vấn chỉ được dùng ở đúng một chỗ. Hãy viết thẳng nó ra.
  • Hiệu năng quan trọng và truy vấn bên dưới tốn kém: bạn phải trả chi phí đó ở mỗi lần đọc. Hãy lưu đệm vào một bảng thật.
  • View phụ thuộc vào một view khác, view đó lại phụ thuộc vào view khác nữa. SQLite xử lý lồng nhau tốt, nhưng một chuỗi ba bốn view khiến SQL thực sự khó theo dõi khi gỡ lỗi.

Tiếp theo: trigger

View và trigger thường đi cùng nhau: mẫu INSTEAD OF giúp ghi được vào view là một trong những lý do chính khiến trigger tồn tại. Trigger còn hữu ích riêng cho việc ghi log kiểm tra, cập nhật dây chuyền và duy trì các bất biến. Đó là trang tiếp theo.

Câu hỏi thường gặp

View trong SQLite là gì?

View là một câu lệnh SELECT được lưu lại mà bạn có thể truy vấn như một bảng. Nó không lưu dữ liệu nào: mỗi lần bạn đọc từ view, SQLite chạy lại truy vấn bên dưới. View hữu ích để đặt tên cho một truy vấn phức tạp một lần rồi dùng lại ở mọi nơi, hoặc để ẩn những cột mà nơi gọi không nên thấy.

Có INSERT hoặc UPDATE qua view trong SQLite được không?

Không trực tiếp. View trong SQLite chỉ đọc được: INSERT, UPDATE và DELETE trên view sẽ thất bại. Bạn có thể giúp view ghi được bằng cách gắn trigger INSTEAD OF để chuyển lệnh ghi thành các thao tác trên những bảng bên dưới.

SQLite có hỗ trợ materialized view không?

Không. SQLite chỉ có view thông thường (view ảo): truy vấn chạy lại mỗi lần bạn đọc từ view. Nếu cần kết quả được lưu đệm, hãy tạo một bảng thật và tự làm mới nó, hoặc dùng trigger để giữ nó đồng bộ với các bảng nguồn.

Làm sao liệt kê tất cả view trong một cơ sở dữ liệu SQLite?

Truy vấn sqlite_master: SELECT name FROM sqlite_master WHERE type = 'view';. Trong CLI, .schema hiển thị các câu lệnh CREATE VIEW và .tables liệt kê view cùng với bảng.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu