Đây là dự kiến, hành vi tài liệu.
Tom Lane giải thích nó ở đây.
Tài liệu hướng dẫn ở đây:
Báo cáo dữ liệu thay đổi trong WITH
được thực hiện đúng một lần, và
luôn hoàn thành , độc lập với việc truy vấn chính đọc tất cả (hoặc thực sự có) của sản lượng của họ. Lưu ý rằng điều này khác với quy tắc SELECT
trong WITH
: như đã nêu trong phần trước, việc thực hiện a SELECT
chỉ được thực hiện khi có truy vấn chính yêu cầu đầu ra của nó .
Nhấn mạnh đậm của tôi. "Dữ liệu sửa đổi" là INSERT
, UPDATE
và DELETE
truy vấn. (Trái ngược với SELECT
.). Hướng dẫn một lần nữa:
Bạn có thể sử dụng báo cáo dữ liệu thay đổi ( INSERT
, UPDATE
hoặc DELETE
) trong WITH
.
Chức năng đúng
CREATE OR REPLACE FUNCTION public.__post_users_id_coin (_coins integer, _userid integer)
RETURNS TABLE (id integer) AS
$func$
UPDATE users u
SET coin = u.coin + _coins -- see below
WHERE u.id = _userid
RETURNING u.id
$func$ LANGUAGE sql COST 100 ROWS 1000 STRICT;
Tôi bỏ các mệnh đề (tiếng ồn) mặc định và
STRICT
là từ đồng nghĩa ngắn choRETURNS NULL ON NULL INPUT
.
Hãy chắc chắn rằng bằng cách nào đó tên tham số không xung đột với tên cột. Tôi đã chuẩn bị trước _
, nhưng đó chỉ là sở thích cá nhân của tôi.
Nếu coin
có thể NULL
tôi đề nghị:
SET coin = CASE WHEN coin IS NULL THEN _coins ELSE coin + _coins END
Nếu users.id
là khóa chính, thì RETURNS TABLE
cũng không ROWs 1000
có nghĩa gì cả. Chỉ một hàng duy nhất có thể được cập nhật / trả lại. Nhưng đó là tất cả bên cạnh điểm chính.
Gọi đúng
Sẽ không có nghĩa gì khi sử dụng RETURNING
mệnh đề và trả về các giá trị từ hàm của bạn nếu bạn sẽ bỏ qua các giá trị được trả về trong cuộc gọi. Nó cũng không có ý nghĩa để phân tách các hàng trả lại với SELECT * FROM ...
nếu bạn bỏ qua chúng.
Chỉ cần trả về hằng số vô hướng ( RETURNING 1
), xác định hàm là RETURNS int
(hoặc thả RETURNING
hoàn toàn và tạo nó RETURNS void
) và gọi nó bằngSELECT my_function(...)
Giải pháp
Vì bạn ...
không thực sự quan tâm đến kết quả
.. chỉ là SELECT
một dạng không đổi của CTE. Nó được đảm bảo được thực hiện miễn là nó được tham chiếu ở bên ngoài SELECT
(trực tiếp hoặc gián tiếp).
WITH test AS (SELECT __post_users_id_coin(10, 1))
SELECT 1 FROM test;
Nếu bạn thực sự có chức năng trả về thiết lập và vẫn không quan tâm đến đầu ra:
WITH test AS (SELECT * FROM __post_users_id_coin(10, 1))
SELECT 1 FROM test LIMIT 1;
Không cần phải trả lại hơn 1 hàng. Hàm vẫn được gọi.
Cuối cùng, không rõ lý do tại sao bạn cần CTE để bắt đầu. Có lẽ chỉ là một bằng chứng về khái niệm.
Quan hệ gần gũi:
Câu trả lời liên quan về SO:
Và xem xét: