我有以下sql的语法错误,花了一个小时,但无法找到postgres文档的任何答案。
CREATE TABLE transaction (userid SMALLINT, point INT, timestamp TIMESTAMPTZ);
CREATE TABLE point (userid SMALLINT PRIMARY KEY, balance1 INT, balance2 INT);
CREATE TABLE settings (userid SMALLINT, bonus INT);
INSERT INTO settings VALUES (1, 10); -- sample data
WITH trans AS (
INSERT INTO transaction (userid, point, timestamp)
VALUES ($1, $2, NOW())
RETURNING *
)
INSERT INTO point (userid, balance1)
SELECT userid, point
FROM trans -- first time
ON CONFLICT (userid) DO UPDATE
SET balance1=point.balance1 + excluded.balance1,
balance2=point.balance2 + excluded.balance1 + settings.bonus
FROM settings -- tried USING, not work
WHERE settings.userid=excluded.userid;
我的问题是如何在更新期间不使用FROM而包含额外的表格?我的目标是将所有内容保留为1个查询。
答案 0 :(得分:1)
我并不完全清楚你要做什么。我理解它的方式是,在settings.bonus
启动时更新行时,您尝试使用on conflict
中的值。
这可以使用UPDATE
部分中的共同相关子查询来完成:
WITH trans (userid, point, timestamp) AS (
INSERT INTO transaction (userid, point, timestamp)
VALUES (1, 1, NOW())
RETURNING *
)
INSERT INTO point (userid, balance1)
SELECT trans.userid, trans.point
FROM trans
ON CONFLICT (userid) DO UPDATE
SET balance1 = point.balance1 + excluded.balance1,
balance2 = point.balance2 + excluded.balance1 + (select s.bonus
from settings s
where s.userid = excluded.userid)
但请注意,balance2
永远不会以这种方式递增,因为在第一个插入时,null
后续更新将尝试向null
添加内容但是任何涉及null的表达式null(null + 5
为null)。
因此,您需要在第一次插入时插入0
,或在执行更新时使用coalesce()
,例如
balance2 = coalesce(point.balance2, 0) + excluded.balance1 + (select ...);
如果该用户settings
中没有行可能,那么您需要在子查询的结果上应用coalesce()
以及:
... excluded.balance1 + coalesce( (select ... ), 0)
另外:您在问题中使用excluded.point
这是不正确的。 excluded
指的是目标表point
,但没有列点 - 您可能意味着:excluded.balance1(因为插入的trans.point
将插入的列)< / p>
无关,但是:timestamp
是列的可怕名称。一个是因为它是一个关键字,但更重要的是因为它没有记录列的用途。是否意味着&#34;创建于&#34;? &#34;有效期至&#34;? &#34;从&#34;开始? &#34;过时了#34;?完全不同的东西?