Hàm của bạn có thể trông giống như sau:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS SETOF transactions AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM transactions
WHERE ' || quote_ident(_col) || ' = $1
LIMIT $2'
USING _val, _limit;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
TRONG PostgreSQL 9.1 trở lên đơn giản hơn với định dạng format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
thoát khỏi các số nhận dạng như quote_ident()
.
Những điểm chính:
-
Bạn đã gặp phải hạn chế của SQL động là bạn không thể sử dụng các tham số cho số nhận dạng. Bạn phải tạo chuỗi truy vấn với tên cột và sau đó thực thi nó.
-
Bạn có thể làm điều đó với các giá trị. Tôi chứng minh việc sử dụng
USING
mệnh đề choEXECUTE
. Cũng lưu ý việc sử dụngquote_ident()
:ngăn chặn việc đưa vào SQL và một số lỗi cú pháp nhất định. -
Tôi cũng đã đơn giản hóa phần lớn chức năng của bạn.
[RETURN QUERY EXECUTE][3]
làm cho mã của bạn ngắn hơn và nhanh hơn. Không cần lặp lại nếu tất cả những gì bạn làm là trả về hàng. -
Tôi sử dụng
IN
có tên để bạn không bị nhầm lẫn với $ -notation trong chuỗi truy vấn.$1
và$2
bên trong chuỗi truy vấn đề cập đến các giá trị được cung cấp trongUSING
chứ không phải tham số đầu vào. -
Tôi đổi thành
SELECT *
vì bạn vẫn phải trả lại toàn bộ hàng để khớp với kiểu trả về đã khai báo. -
Cuối cùng nhưng không kém phần quan trọng:Hãy chắc chắn xem hướng dẫn sử dụng phải nói gì về các hàm được khai báo
SECURITY DEFINER
.
LOẠI TRỞ LẠI
Nếu bạn không muốn trả lại toàn bộ hàng, một khả năng thuận tiện là:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Sau đó, bạn không phải cung cấp danh sách định nghĩa cột với mọi lệnh gọi và có thể đơn giản hóa thành:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);