**已关闭。**此问题为not reproducible or was caused by typos。目前不接受答复。
此问题是由打印错误或无法再重现的问题引起的。虽然类似的问题在这里可能是on-topic,但这个问题的解决方式不太可能帮助未来的读者。
5天前关闭。
Improve this question
我有一个users
表,其中包含id
、name
、created_at
和updated_at
。created_at
和updated_at
都具有默认为当前时间戳的默认值。我尝试在此表中添加如下内容。
INSERT INTO users (
id,
name,
created_at,
updated_at
) VALUES (
'0e22e5b9-3826-401c-824b-ba12b1b4eb0a'
'Some User',
NOW(),
NOW()
) ON CONFLICT (
id
) DO UPDATE SET
name = excluded."name",
updated_at = excluded."updated_at"
RETURNING
"id",
"name",
"created_at",
"updated_at";
我想确保当插入发生时,“created_at”和“updated_at”都被设置,但是当有冲突并且只发生更新时,那么只有“updated_at”被更新,我想返回最后一行。我希望如果我有一个现有的行
| id|姓名|创建于|更新_at|
| - -----|- -----|- -----|- -----|
| 1| 0e22e5b9-3826-401c-824b-ba12b1b4eb0a|一些名字|2023年3月1日|
两天后我更新了名称,我会从return语句中得到类似这样的结果,其中只有updated_at
发生了变化
| id|姓名|创建于|更新_at|
| - -----|- -----|- -----|- -----|
| 1| 0e22e5b9-3826-401c-824b-ba12b1b4eb0a| Abcd名称|2023年3月1日|
但是我得到的结果是created_at
和updated_at
都被更改了
| id|姓名|创建于|更新_at|
| - -----|- -----|- -----|- -----|
| 1| 0e22e5b9-3826-401c-824b-ba12b1b4eb0a| Abcd名称|2023年3月3日|
此问题仅与查询运行后的返回值有关,表中的实际值仍然正确。我假设这个行为与RETURNING
命令如何与upsert查询交互有关,但是我在任何地方都找不到关于这个行为的文档。我知道有解决办法,但我只是想知道为什么这个特定的方法不起作用。这是PostreSQL的错误还是预期行为?
1条答案
按热度按时间fafcakar1#
您所遇到的行为是PostgreSQL在使用
RETURNING
子句与INSERT ...
ON CONFLICT ...
DO UPDATE
语句组合时的预期行为。此行为并不特定于RETURNING
子句,而是ON CONFLICT ...
DO UPDATE
语句的工作方式。当发生冲突并触发
DO UPDATE
子句时,SET
子句中指定的所有列都将被更新,无论它们是否在EXCLUDED
行中实际更改。这是DO UPDATE
子句的默认行为。在本例中,created_at和updated_at都在
SET
子句中指定,因此即使created_at保持不变,它仍然会使用excluded.“created_at”中的值进行更新,这与本例中的NOW()
相同。要实现所需的行为,其中
created_at
在更新期间保持不变,您可以按如下方式修改查询:通过显式设置
created_at = users.created_at
,可以确保created_at
列在更新期间保留其原始值,并且只有updated_at
列得到更新。这种行为不是bug,而是PostgreSQL实现
ON CONFLICT ...
DO UPDATE
语句时的一种设计选择。它旨在提供在冲突期间更新列的灵活性,即使值没有更改。