Ini diharapkan, perilaku yang terdokumentasi.
Tom Lane menjelaskannya di sini.
Didokumentasikan dalam manual di sini:
Pernyataan pengubah data di WITHdieksekusi tepat sekali, dan
selalu sampai selesai , terlepas dari apakah kueri utama membaca semua (atau memang ada) dari output mereka. Perhatikan bahwa ini berbeda dari aturan untuk SELECTdi WITH: seperti yang dinyatakan dalam bagian sebelumnya, eksekusi a SELECThanya dilakukan sejauh permintaan utama menuntut outputnya .
Penekanan berani saya. "Memodifikasi data" adalah INSERT, UPDATEdan DELETEkueri. (Berbeda dengan SELECT.). Manual sekali lagi:
Anda dapat menggunakan laporan data memodifikasi ( INSERT, UPDATE, atau DELETE) di WITH.
Fungsi yang tepat
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;
Saya menjatuhkan klausa default (noise) dan
STRICTmerupakan sinonim singkat untukRETURNS NULL ON NULL INPUT .
Pastikan entah bagaimana nama parameter tidak bertentangan dengan nama kolom. Saya menambahkan _, tapi itu hanya preferensi pribadi saya.
Jika coinbisa NULLsaya sarankan:
SET coin = CASE WHEN coin IS NULL THEN _coins ELSE coin + _coins END
Jika users.idadalah kunci utama, maka keduanya RETURNS TABLEtidak ROWs 1000masuk akal. Hanya satu baris yang dapat diperbarui / dikembalikan. Tapi itu semua di samping poin utama.
Panggilan yang tepat
Tidak masuk akal untuk menggunakan RETURNINGklausa dan mengembalikan nilai dari fungsi Anda jika Anda akan mengabaikan nilai yang dikembalikan dalam panggilan. Juga tidak masuk akal untuk menguraikan baris yang dikembalikan dengan SELECT * FROM ...jika Anda mengabaikannya.
Cukup kembalikan konstanta skalar ( RETURNING 1), tentukan fungsinya sebagai RETURNS int(atau jatuhkan RETURNINGsama sekali dan buatlah RETURNS void) dan sebut denganSELECT my_function(...)
Larutan
Karena kamu ...
tidak terlalu peduli dengan hasilnya
.. hanya SELECTbentuk konstan CTE. Ini dijamin akan dieksekusi selama itu direferensikan di luar SELECT(langsung atau tidak langsung).
WITH test AS (SELECT __post_users_id_coin(10, 1))
SELECT 1 FROM test;
Jika Anda benar-benar memiliki fungsi set-return dan masih tidak peduli dengan hasilnya:
WITH test AS (SELECT * FROM __post_users_id_coin(10, 1))
SELECT 1 FROM test LIMIT 1;
Tidak perlu mengembalikan lebih dari 1 baris. Fungsi ini masih dipanggil.
Akhirnya, tidak jelas mengapa Anda membutuhkan CTE untuk memulai. Mungkin hanya bukti konsep.
Erat terkait:
Jawaban terkait pada SO:
Dan pertimbangkan: