Просто надеюсь подтвердить мои наблюдения и получить объяснение того, почему это происходит.
У меня есть функция, определенная как:
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
Когда я вызываю эту функцию из CTE, она выполняет команду SQL, но не вызывает функцию, например:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
1 -- Select 1 but update not performed
С другой стороны, если я вызываю функцию из CTE и затем выбираю результат CTE (или вызываю функцию напрямую без CTE), он выполняет команду SQL и вызывает функцию, например:
WITH test AS
(SELECT * FROM __post_users_id_coin(10, 1))
SELECT
*
FROM
test -- Select result and update performed
или
SELECT * FROM __post_users_id_coin(10,1)
Поскольку меня не волнует результат функции (просто нужно выполнить обновление), есть ли способ заставить это работать без выбора результата CTE?
источник
Это ожидаемое, документированное поведение.
Том Лейн объясняет это здесь.
Документировано в руководстве здесь:
Жирный акцент мой. «Данные модифицирующие» являются
INSERT
,UPDATE
иDELETE
запросы. (В отличие отSELECT
.). Руководство еще раз:Правильная функция
Я отбросил предложения по умолчанию (шум) и
STRICT
является коротким синонимом дляRETURNS NULL ON NULL INPUT
.Убедитесь, что имена параметров не конфликтуют с именами столбцов. Я в начале
_
, но это только мое личное предпочтение.Если
coin
можноNULL
я предлагаю:Если
users.id
это первичный ключ, тоRETURNS TABLE
ниROWs 1000
имеет смысла. Только одна строка может быть обновлена / возвращена. Но это все помимо основного.Правильный вызов
Нет смысла использовать
RETURNING
предложение и возвращать значения из вашей функции, если вы все равно собираетесь игнорировать возвращаемые значения в вызове. Также нет смысла декомпозировать возвращаемые строки сSELECT * FROM ...
если вы все равно их игнорируете.Просто верните скалярную константу (
RETURNING 1
), определите функцию какRETURNS int
(илиRETURNING
вообще удалите и сделайте ееRETURNS void
) и вызовите ее с помощьюSELECT my_function(...)
Решение
Так как ты ...
.. просто
SELECT
постоянная форма CTE. Он гарантированно будет выполняться до тех пор, пока на него ссылаются во внешнемSELECT
(прямо или косвенно).Если у вас действительно есть функция, возвращающая множество, и вы все равно не заботитесь о выводе:
Не нужно возвращать более 1 строки. Функция все еще вызывается.
Наконец, неясно, зачем вам нужен CTE для начала. Вероятно, просто доказательство концепции.
Тесно связаны:
Соответствующий ответ на SO:
И рассмотрим:
источник
INSERT
до того, какUPDATE
внутри той же функции обертывания - нет доступных транзакций.test
вWITH test AS (SELECT * FROM __post_users_id_coin(10, 1)) SELECT ... LIMIT 1;
считается изменением КТРА или нет?SELECT
не является «изменяющим данные» согласно терминологии CTE. Я добавил некоторые разъяснения выше. Это ответственность пользователя, если он (и) добавляет код в функцию, которая изменяет данные за кулисами.