Hanya berharap untuk mengkonfirmasi pengamatan saya dan mendapatkan penjelasan tentang mengapa ini terjadi.
Saya memiliki fungsi yang didefinisikan sebagai:
CREATE OR REPLACE FUNCTION "public"."__post_users_id_coin" ("coins" integer, "userid" integer) RETURNS TABLE (id integer) AS '
UPDATE
users
SET
coin = coin + coins
WHERE
userid = users.id
RETURNING
users.id' LANGUAGE "sql" COST 100 ROWS 1000
VOLATILE
RETURNS NULL ON NULL INPUT
SECURITY INVOKER
Ketika saya memanggil fungsi ini dari CTE, itu mengeksekusi perintah SQL tetapi tidak memicu fungsi, misalnya:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
1 -- Select 1 but update not performed
Di sisi lain, jika saya memanggil fungsi dari CTE dan kemudian memilih hasil CTE (atau memanggil fungsi langsung tanpa CTE) itu mengeksekusi perintah SQL dan memicu fungsi, misalnya:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
*
FROM
test -- Select result and update performed
atau
SELECT * FROM __post_users_id_coin(10,1)
Karena saya tidak terlalu peduli dengan hasil fungsi (hanya perlu melakukan pembaruan) apakah ada cara agar ini berfungsi tanpa memilih hasil CTE?
sumber
Ini diharapkan, perilaku yang terdokumentasi.
Tom Lane menjelaskannya di sini.
Didokumentasikan dalam manual di sini:
Penekanan berani saya. "Memodifikasi data" adalah
INSERT
,UPDATE
danDELETE
kueri. (Berbeda denganSELECT
.). Manual sekali lagi:Fungsi yang tepat
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
bisaNULL
saya sarankan:Jika
users.id
adalah kunci utama, maka keduanyaRETURNS TABLE
tidakROWs 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 denganSELECT * FROM ...
jika Anda mengabaikannya.Cukup kembalikan konstanta skalar (
RETURNING 1
), tentukan fungsinya sebagaiRETURNS int
(atau jatuhkanRETURNING
sama sekali dan buatlahRETURNS void
) dan sebut denganSELECT my_function(...)
Larutan
Karena kamu ...
.. hanya
SELECT
bentuk konstan CTE. Ini dijamin akan dieksekusi selama itu direferensikan di luarSELECT
(langsung atau tidak langsung).Jika Anda benar-benar memiliki fungsi set-return dan masih tidak peduli dengan hasilnya:
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:
sumber
INSERT
sebelum keUPDATE
dalam fungsi pembungkus yang sama - tidak ada transaksi yang tersedia.test
diWITH test AS (SELECT * FROM __post_users_id_coin(10, 1)) SELECT ... LIMIT 1;
dianggap sebagai CTE memodifikasi atau tidak?SELECT
bukan "pengubah data" menurut terminologi CTE. Saya menambahkan beberapa klarifikasi di atas. Adalah tanggung jawab pengguna jika ia menambahkan kode ke fungsi yang mengubah data di balik tirai.