Возврат нескольких значений из запроса UPDATE в PostgreSQL
Я новичок в написании функций БД и мне нужно вернуть значение last_login_at как OUT
параметр при выполнении UPDATE
запрос.
Вот фрагмент моей функции:
...
LOOP
UPDATE "user" SET
last_login_at = current_timestamp,
first_name = p_first_name,
last_name = p_last_name,
WHERE ext_user_id = p_ext_user_id AND platform_id = p_platform_id
RETURNING id INTO v_user_id;
is_new := false;
// The next 'CASE' is not valid - Need to replace it with a valid one.
has_logged_in_today = CASE
WHEN date_part('day', age(current_timestamp, last_login_at)) > 1
THEN true
ELSE false
END;
IF FOUND THEN
EXIT;
END IF;
..
..
END LOOP;
Можно ли сделать несколько RETURNING x INTO y
?
Можем ли мы использовать CASE
заявление в RETURNING x INTO y
?
РЕДАКТИРОВАТЬ
Я смог добиться лучших результатов, и теперь это выглядит так:
...
LOOP
UPDATE "user" SET
login_consecutive_days = CASE
WHEN date_part('day', age(current_timestamp, last_login_at)) > 1
THEN 0
ELSE login_consecutive_days + date_part('day', age(current_timestamp, last_login_at))
END,
login_max_consecutive_days = CASE
WHEN date_part('day', age(current_timestamp, last_login_at)) = 1
AND (login_consecutive_days+1 > login_max_consecutive_days)
THEN login_consecutive_days+1
ELSE login_max_consecutive_days
END,
last_login_at = current_timestamp,
num_sessions = num_sessions + 1,
last_update_source = 'L',
first_name = p_first_name,
last_name = p_last_name,
additional_data = p_additional_data
WHERE ext_user_id = p_ext_user_id AND platform_id = p_platform_id
RETURNING id,
CASE
WHEN date_part('day', age(current_timestamp, last_login_at)) = 0
THEN true
ELSE false
END
INTO v_user_id, is_first_login_today;
is_new := false;
IF FOUND THEN
EXIT;
END IF;
...
Единственная проблема с этим заключается в том, что в точке RETURNING
last_login_at
уже был обновлен так CASE
всегда возвращается TRUE
,
Есть ли волшебное решение моей проблемы?
2 ответа
Есть ли волшебное решение моей проблемы?
На самом деле, есть: присоединиться к другому экземпляру "user"
стол в FROM
пункт:
UPDATE "user" u
SET login_consecutive_days = ... -- unqualified column name
FROM "user" u1
WHERE u.ext_user_id = p_ext_user_id
AND u.platform_id = p_platform_id
AND u.id = u1.id -- must be unique not null (like the PK)
RETURNING u.id, (u1.last_login_at < now() + interval '1 day')
INTO v_user_id, is_first_login_today;
is_new := false;
EXIT WHEN FOUND;
Теперь псевдоним таблицы u
относится к пост-UPDATE
состояние таблицы, но u1
ссылается на снимок в начале запроса.
Детальное объяснение:
Табличная квалификация всех ссылок на столбцы должна быть однозначной, что никогда не является плохой идеей, но после самостоятельного объединения это требуется.
Руководство по короткому синтаксисуEXIT WHEN FOUND
,
Вы можете использовать любое выражение вRETURNING
пункт, в том числеCASE
заявления. Просто для этого есть более простой и дешевый способ:
CASE WHEN date_part('day', age(current_timestamp, last_login_at)) = 0
THEN true ELSE false END
Шаг 1:
CASE WHEN last_login_at < now() + interval '1 day'
THEN true ELSE false END
Шаг 2:
(last_login_at < now() + interval '1 day')
Просто используйте boolean
результат. Если last_login_at
являетсяNULL
, ты получаешьNULL
,
Asides:
Что касается остальной части запроса: выражения могут быть упрощены,LOOP
подозрительно, вы никогда не должны использовать зарезервированные слова в качестве идентификаторов, даже если двойные кавычки делают это возможным ("user"
), алгоритм, кажется, зависит от выполнения с точными 24-часовыми интервалами, что подвержено ошибкам.
Вы можете вернуть несколько столбцов с синтаксисом:
UPDATE "user" SET
last_login_at = current_timestamp,
first_name = p_first_name,
last_name = p_last_name,
WHERE ext_user_id = p_ext_user_id AND platform_id = p_platform_id
RETURNING id, last_login_at
INTO v_user_id, v_login_at;
Возвращаемое предложение следует большинству правил списка полей SELECT, поэтому вы можете добавить столько столбцов, сколько вам нужно.