Solo espero confirmar mi observación y obtener una explicación sobre por qué sucede esto.
Tengo una función definida como:
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
Cuando llamo a esta función desde un CTE, ejecuta el comando SQL pero no activa la función, por ejemplo:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
1 -- Select 1 but update not performed
Por otro lado, si llamo a la función desde un CTE y luego selecciono el resultado del CTE (o llamo a la función directamente sin CTE), ejecuta el comando SQL y activa la función, por ejemplo:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
*
FROM
test -- Select result and update performed
o
SELECT * FROM __post_users_id_coin(10,1)
Como realmente no me importa el resultado de la función (solo la necesito para realizar la actualización), ¿hay alguna forma de hacer que esto funcione sin seleccionar el resultado del CTE?
fuente

Esto se espera, comportamiento documentado.
Tom Lane lo explica aquí.
Documentado en el manual aquí:
El énfasis audaz es mío. "Datos modificadores" son
INSERT,UPDATEyDELETEconsultas. (A diferencia deSELECT). El manual una vez más:Función adecuada
Eliminé las cláusulas predeterminadas (ruido) y
STRICTes el sinónimo corto deRETURNS NULL ON NULL INPUT.Asegúrese de alguna manera de que los nombres de los parámetros no entren en conflicto con los nombres de las columnas. Prefiero
_, pero esa es solo mi preferencia personal.Si
coinpuede serNULLsugiero:Si
users.ides la clave principal, entoncesRETURNS TABLEniROWs 1000tiene sentido. Solo se puede actualizar / devolver una sola fila. Pero eso está al lado del punto principal.Llamada adecuada
No tiene sentido usar la
RETURNINGcláusula y devolver los valores de su función si va a ignorar los valores devueltos en la llamada de todos modos. Tampoco tiene sentido descomponer filas devueltasSELECT * FROM ...si las ignora de todos modos.Simplemente devuelva una constante escalar (
RETURNING 1), defina la función comoRETURNS int(o suelte porRETURNINGcompleto y hágalaRETURNS void) y llámela conSELECT my_function(...)Solución
Desde que tu ...
.. solo
SELECTuna forma constante del CTE. Se garantiza que se ejecutará siempre que se haga referencia en el exteriorSELECT(directa o indirectamente).Si realmente tiene una función de retorno de conjunto y aún no le importa la salida:
No es necesario devolver más de 1 fila. La función todavía se llama.
Finalmente, no está claro por qué necesita el CTE para empezar. Probablemente solo una prueba de concepto.
Estrechamente relacionada:
Respuesta relacionada sobre SO:
Y considere:
fuente
INSERTantes deUPDATEdentro de la misma función de ajuste : no hay transacciones disponibles.testdeWITH test AS (SELECT * FROM __post_users_id_coin(10, 1)) SELECT ... LIMIT 1;considerar un CTE o no la modificación?SELECTno está "modificando datos" de acuerdo con la terminología CTE. Agregué algunas aclaraciones arriba. Es responsabilidad del usuario si agrega código a una función que modifica los datos detrás de las cortinas.