Ini diharapkan, perilaku yang terdokumentasi.
Tom Lane menjelaskannya di sini.
Didokumentasikan dalam manual di sini:
Pernyataan pengubah data di WITH
dieksekusi 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 SELECT
di WITH
: seperti yang dinyatakan dalam bagian sebelumnya, eksekusi a SELECT
hanya dilakukan sejauh permintaan utama menuntut outputnya .
Penekanan berani saya. "Memodifikasi data" adalah INSERT
, UPDATE
dan DELETE
kueri. (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
STRICT
merupakan 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 coin
bisa NULL
saya sarankan:
SET coin = CASE WHEN coin IS NULL THEN _coins ELSE coin + _coins END
Jika users.id
adalah kunci utama, maka keduanya RETURNS TABLE
tidak ROWs 1000
masuk akal. Hanya satu baris yang dapat diperbarui / dikembalikan. Tapi itu semua di samping poin utama.
Panggilan yang tepat
Tidak masuk akal untuk menggunakan RETURNING
klausa 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 RETURNING
sama sekali dan buatlah RETURNS void
) dan sebut denganSELECT my_function(...)
Larutan
Karena kamu ...
tidak terlalu peduli dengan hasilnya
.. hanya SELECT
bentuk 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: