Điều này có thể được đơn giản hóa và cải thiện hơn nữa:
CREATE OR REPLACE FUNCTION some_f(_tbl regclass, OUT result integer)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (EXISTS (SELECT FROM %s WHERE id = 1))::int', _tbl)
INTO result;
END
$func$;
Gọi bằng tên đủ điều kiện giản đồ (xem bên dưới):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Hoặc:
SELECT some_f('"my very uncommon table name"');
Những điểm chính
Sử dụng OUT
tham số để đơn giản hóa chức năng. Bạn có thể chọn trực tiếp kết quả của SQL động vào nó và được thực hiện. Không cần các biến và mã bổ sung.
EXISTS
làm chính xác những gì bạn muốn. Bạn nhận được true
nếu hàng tồn tại hoặc false
nếu không thì. Có nhiều cách khác nhau để thực hiện việc này, EXISTS
thường hiệu quả nhất.
Có vẻ như bạn muốn một số nguyên quay lại, vì vậy tôi truyền boolean
kết quả từ EXISTS
thành integer
, mang lại chính xác những gì bạn đã có. Tôi sẽ trả lại boolean thay vào đó.
Tôi sử dụng loại mã định danh đối tượng regclass
làm kiểu đầu vào cho _tbl
. Điều đó thực hiện mọi thứ quote_ident(_tbl)
hoặc định dạng format('%I', _tbl)
sẽ làm được, nhưng tốt hơn, bởi vì:
-
.. nó ngăn chặn SQL injection cũng như vậy.
-
.. nó không thành công ngay lập tức và duyên dáng hơn nếu tên bảng không hợp lệ / không tồn tại / ẩn đối với người dùng hiện tại. (Một
regclass
tham số chỉ áp dụng cho hiện tại bảng.) -
.. nó hoạt động với tên bảng đủ điều kiện giản đồ, trong đó
quote_ident(_tbl)
đơn giản hoặc định dạngformat(%I)
sẽ không thành công bởi vì họ không thể giải quyết sự mơ hồ. Bạn sẽ phải chuyển và thoát khỏi tên lược đồ và bảng riêng biệt.
Nó chỉ hoạt động cho hiện có bảng, rõ ràng.
Tôi vẫn sử dụng format()
, bởi vì nó đơn giản hóa cú pháp (và để chứng minh cách nó được sử dụng), nhưng với %s
thay vì %I
. Thông thường, các truy vấn phức tạp hơn nên format()
giúp nhiều hơn. Đối với ví dụ đơn giản, chúng ta cũng có thể nối:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Không cần xác định bảng điều kiện id
trong khi chỉ có một bảng duy nhất trong FROM
danh sách. Không có sự mơ hồ nào có thể có trong ví dụ này. (Động) Các lệnh SQL bên trong EXECUTE
có phạm vi riêng biệt , các biến hoặc tham số hàm không hiển thị ở đó - trái ngược với các lệnh SQL thuần túy trong thân hàm.
Đây là lý do tại sao bạn luôn luôn thoát đầu vào của người dùng cho SQL động đúng cách:
db <> fiddle here trình diễn SQL injection
Old sqlfiddle