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
,UPDATE
yDELETE
consultas. (A diferencia deSELECT
). El manual una vez más:Función adecuada
Eliminé las cláusulas predeterminadas (ruido) y
STRICT
es 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
coin
puede serNULL
sugiero:Si
users.id
es la clave principal, entoncesRETURNS TABLE
niROWs 1000
tiene sentido. Solo se puede actualizar / devolver una sola fila. Pero eso está al lado del punto principal.Llamada adecuada
No tiene sentido usar la
RETURNING
clá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 porRETURNING
completo y hágalaRETURNS void
) y llámela conSELECT my_function(...)
Solución
Desde que tu ...
.. solo
SELECT
una 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
INSERT
antes deUPDATE
dentro de la misma función de ajuste : no hay transacciones disponibles.test
deWITH test AS (SELECT * FROM __post_users_id_coin(10, 1)) SELECT ... LIMIT 1;
considerar un CTE o no la modificación?SELECT
no 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.