PostgreSQL 9.1 trở lên
format()
có một cách tích hợp để thoát khỏi số nhận dạng. Đơn giản hơn trước:
CREATE OR REPLACE FUNCTION foo_before()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('INSERT INTO %I.%I SELECT $1.*'
, TG_TABLE_SCHEMA, TG_TABLE_NAME || 'shadow')
USING OLD;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
Hoạt động với VALUES
cả biểu thức.
db <> fiddle here
Sqlfiddle cũ.
Những điểm chính
- Sử dụng
format()
hoặcquote_ident()
để trích dẫn số nhận dạng (tự động và chỉ khi cần thiết), do đó bảo vệ khỏi việc đưa vào SQL và vi phạm cú pháp đơn giản.
Điều này là cần thiết , ngay cả với tên bảng của riêng bạn! - Lược đồ xác định điều kiện cho tên bảng. Tùy thuộc vào
search_path
hiện tại Nếu không, việc đặt một tên bảng trống có thể giải quyết cho một bảng khác có cùng tên trong một giản đồ khác. - Sử dụng
EXECUTE
cho các câu lệnh DDL động. - Chuyển các giá trị an toàn với
USING
mệnh đề. - Tham khảo hướng dẫn chi tiết về Thực thi các lệnh động trong plpgsql.
- Lưu ý rằng
RETURN OLD;
trong hàm kích hoạt là bắt buộc đối với trình kích hoạtBEFORE DELETE
. Chi tiết trong sách hướng dẫn tại đây.
Bạn nhận được thông báo lỗi trong phiên bản gần như thành công của bạn vì OLD
không hiển thị bên trong EXECUTE
. Và nếu bạn muốn nối các giá trị riêng lẻ của hàng đã phân tách như bạn đã thử, bạn phải chuẩn bị biểu diễn văn bản của mỗi cột đơn với quote_literal()
để đảm bảo cú pháp hợp lệ. Bạn cũng sẽ phải biết trước các tên cột để xử lý chúng hoặc truy vấn danh mục hệ thống - điều này đi ngược lại ý tưởng của bạn về việc có một chức năng kích hoạt động, đơn giản ...
Giải pháp của tôi tránh được tất cả những biến chứng này. Cũng được đơn giản hóa một chút.
PostgreSQL 9.0 trở xuống
format()
vẫn chưa có sẵn, vì vậy:
CREATE OR REPLACE FUNCTION foo_before()
RETURNS trigger AS
$func$
BEGIN
EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA)
|| '.' || quote_ident(TG_TABLE_NAME || 'shadow')
|| ' SELECT $1.*'
USING OLD;
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
Có liên quan:
- Cách sử dụng động TG_TABLE_NAME trong PostgreSQL 8.2?