Làm thế nào để tạo một hàm tạm thời trong PostgreSQL?


82

Tôi phải thực hiện một vòng lặp trong cơ sở dữ liệu. Đây chỉ là yêu cầu một lần. Sau khi thực thi chức năng, tôi đang bỏ chức năng ngay bây giờ.

Có cách tiếp cận tốt nào để tạo các hàm tạm thời / dùng một lần không?

Câu trả lời:


115

Tôi cần biết cách sử dụng nhiều thời gian trong một kịch bản mà tôi đang viết. Hóa ra bạn có thể tạo một hàm tạm thời bằng lược đồ pg_temp. Đây là một lược đồ được tạo theo yêu cầu cho kết nối của bạn và là nơi các bảng tạm thời được lưu trữ. Khi kết nối của bạn bị đóng hoặc hết hạn, lược đồ này sẽ bị loại bỏ. Hóa ra nếu bạn tạo một hàm trên lược đồ này, thì lược đồ sẽ được tạo tự động. Vì thế,

create function pg_temp.testfunc() returns text as 
$$ select 'hello'::text $$ language sql;

sẽ là một chức năng sẽ hoạt động miễn là kết nối của bạn còn tồn tại. Không cần gọi lệnh thả.


61

Một vài lưu ý bổ sung cho mẹo thông minh trong câu trả lời của @ crowmagnumb :

  • Theo Tom Lane, hàm phải đủ điều kiện giản đồ , ngay cả khi pg_tempở trong search_path(như mặc định), theo Tom Lane để ngăn chặn ngựa thành Troy:
CREATE FUNCTION pg_temp.f_inc(int)
  RETURNS int AS 'SELECT $1 + 1' LANGUAGE sql IMMUTABLE;

SELECT pg_temp.f_inc(42);
f_inc
-----
43
  • Một hàm được tạo trong lược đồ tạm thời chỉ hiển thị trong cùng một phiên (giống như bảng tạm thời). Nó ẩn đối với tất cả các phiên khác (ngay cả đối với cùng một vai trò). Bạn có thể truy cập chức năng với vai trò khác trong cùng một phiên sau đó SET ROLE.

  • Bạn thậm chí có thể tạo một chỉ mục chức năng dựa trên chức năng "tạm thời" này:

    CREATE INDEX foo_idx ON tbl (pg_temp.f_inc(id));
    

    Từ đó tạo ra một chỉ mục đơn giản bằng cách sử dụng một hàm tạm thời trên một bảng không tạm thời. Chỉ mục như vậy sẽ hiển thị cho tất cả các phiên nhưng vẫn chỉ hợp lệ cho phiên tạo. Người lập kế hoạch truy vấn sẽ không sử dụng chỉ mục chức năng, nơi biểu thức không được lặp lại trong truy vấn. Vẫn là một thủ thuật bẩn thỉu. Nó sẽ tự động bị loại bỏ khi phiên đóng cửa - như một đối tượng phụ thuộc. Cảm giác như thế này không được phép chút nào ...


Nếu bạn chỉ cần thực thi một hàm lặp đi lặp lại và tất cả những gì bạn cần là SQL, hãy xem xét một câu lệnh chuẩn bị thay thế. Nó hoạt động giống như một hàm SQL tạm thời bị chết vào cuối phiên. Tuy nhiên, không phải điều tương tự và chỉ có thể được sử dụng bởi chính nó EXECUTE, không được lồng trong một truy vấn khác. Thí dụ:

PREPARE upd_tbl AS
UPDATE tbl t SET set_name = $2 WHERE tbl_id = $1;

Gọi:

EXECUTE upd_tbl(123, 'foo_name');

Chi tiết:


30

Nếu bạn đang sử dụng phiên bản 9.0, bạn có thể thực hiện việc này với câu lệnh DO mới:

http://www.postgresql.org/docs/current/static/sql-do.html

Với các phiên bản trước, bạn sẽ cần tạo hàm, gọi hàm và thả lại.


4
... Nó hữu ích cho việc viết script trên terminal, nhưng bạn không thể gọi nó lại, giống như một "hàm vô nghĩa" (hoặc lambda), vì vậy trạng thái DO không quá hữu ích như một "hàm tạm thời".
Peter Krauss

@PeterKrauss: nếu bạn muốn gọi lại nó, bạn cần tạo một hàm thực.
a_horse_with_no_name

Tất nhiên a_hourse của tôi :-) Tôi chỉ hiển thị đường dẫn lý thuyết cho việc triển khai "tạm thời" ... Đây là lý do tại sao câu trả lời tốt hơn (có thể với PostgreSQL), cho câu hỏi chính, là pg_temp.foo(). Tôi không hiểu tại sao (!?) Hôm nay, 2014, với các ví dụ đơn giản và quá nhanh như Lua , ngôn ngữ SQL DML không thể cung cấp các hàm lambda (!).
Peter Krauss

7
Ngoài ra, các DOcâu lệnh không được có tham số đầu vào và không thể trả về kết quả, ngược lại với các hàm.
Daniel Vérité

2
Nếu nó không trả về, chúng ta có nên gọi nó là một "hàm" không?
AndreKR

-4

Đối với các thủ tục quảng cáo, con trỏ không quá tệ. Tuy nhiên, chúng quá kém hiệu quả để sử dụng trong sản xuất.

Họ sẽ cho phép bạn dễ dàng lặp lại các kết quả sql trong db.


6
Tại sao bạn cho rằng con trỏ không hiệu quả trong PostgreSQL?
Frank Heikens

2
Con trỏ giữ một kết nối cơ sở dữ liệu khi vòng lặp. Một trang web có hàng trăm con trỏ chạy dài sẽ làm chết đói các kết nối và khiến trang web / cơ sở dữ liệu bị bó hẹp.
Byron Whitlock
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.