Возврат нескольких значений из запроса 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, поэтому вы можете добавить столько столбцов, сколько вам нужно.

Обновить документы

Другие вопросы по тегам