从 PostgreSQL 中的更新查询返回多个值
Returning multiple values from UPDATE query in PostgreSQL
我是编写数据库函数的新手,在执行 UPDATE
查询时,我需要 return 'last_login_at' 的值作为 OUT
参数。
这是我的函数的一个片段:
...
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
?
我们可以在 RETURNING x INTO y
中使用 CASE
语句吗?
编辑
我能够获得更好的结果,现在它看起来像这样:
...
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
总是 returns TRUE
。
有什么神奇的方法可以解决我的问题吗?
您可以 return 多个列,语法为:
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;
returning 子句遵循 SELECT 字段列表的大部分规则,因此您可以根据需要添加任意数量的列。
Is there a magical solution to my problem?
实际上,有:在FROM
子句中加入"user"
table的另一个实例:
UPDATE "user" <b>u</b>
SET login_consecutive_days = ... -- unqualified column name
<b>FROM "user" u1</b>
WHERE <b>u.</b>ext_user_id = p_ext_user_id
AND <b>u.</b>platform_id = p_platform_id
AND <b>u.</b>id = <b>u1.</b>id -- must be unique not null (like the PK)
RETURNING <b>u.</b>id, (<b>u1</b>.last_login_at < now() + interval '1 day')
INTO v_user_id, is_first_login_today;
is_new := false;
EXIT WHEN FOUND;
现在,table 别名 u
指的是 table 的 post-UPDATE
状态,但 u1
指的是查询开始时的快照。
详细解释:
- Return pre-UPDATE Column Values Using SQL Only - PostgreSQL Version
Table - 将所有列引用限定为明确的,这绝不是一个坏主意,但在自连接之后它是必需的。
The manual about the short syntax 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
.
旁白:
至于查询的其余部分:表达式可以简化,LOOP
是可疑的,你应该 never 使用 reserved words 作为标识符,即使双引号使有可能("user"
),算法似乎依赖于 exact 24 小时间隔执行,这很容易出错。
我是编写数据库函数的新手,在执行 UPDATE
查询时,我需要 return 'last_login_at' 的值作为 OUT
参数。
这是我的函数的一个片段:
...
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
?
我们可以在 RETURNING x INTO y
中使用 CASE
语句吗?
编辑
我能够获得更好的结果,现在它看起来像这样:
...
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
总是 returns TRUE
。
有什么神奇的方法可以解决我的问题吗?
您可以 return 多个列,语法为:
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;
returning 子句遵循 SELECT 字段列表的大部分规则,因此您可以根据需要添加任意数量的列。
Is there a magical solution to my problem?
实际上,有:在FROM
子句中加入"user"
table的另一个实例:
UPDATE "user" <b>u</b>
SET login_consecutive_days = ... -- unqualified column name
<b>FROM "user" u1</b>
WHERE <b>u.</b>ext_user_id = p_ext_user_id
AND <b>u.</b>platform_id = p_platform_id
AND <b>u.</b>id = <b>u1.</b>id -- must be unique not null (like the PK)
RETURNING <b>u.</b>id, (<b>u1</b>.last_login_at < now() + interval '1 day')
INTO v_user_id, is_first_login_today;
is_new := false;
EXIT WHEN FOUND;
现在,table 别名 u
指的是 table 的 post-UPDATE
状态,但 u1
指的是查询开始时的快照。
详细解释:
- Return pre-UPDATE Column Values Using SQL Only - PostgreSQL Version
Table - 将所有列引用限定为明确的,这绝不是一个坏主意,但在自连接之后它是必需的。
The manual about the short syntax 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
.
旁白:
至于查询的其余部分:表达式可以简化,LOOP
是可疑的,你应该 never 使用 reserved words 作为标识符,即使双引号使有可能(),算法似乎依赖于 exact 24 小时间隔执行,这很容易出错。"user"