【问题标题】:WITH... UPDATE in PostgresQL与...在 PostgresQL 中更新
【发布时间】:2025-12-11 22:45:01
【问题描述】:

我正在尝试使用需要在 UPDATE 语句中多次出现的复杂表达式来更新表(在 pgsql 中)。 WITH 似乎很适合这个:

WITH newtz AS (SELECT timezone FROM timezonebyzipcode WHERE zip=(SELECT zip_code FROM company WHERE id=company_id))
UPDATE cross_rental
SET return_timezone=newtz
return_time=(return_time AT TIME ZONE return_timezone) AT TIME ZONE newtz
WHERE return_to='Vendor' AND return_timezone<>newtz

不幸的是,它不起作用:

ERROR:  syntax error at or near "UPDATE"
LINE 2: UPDATE cross_rental
        ^

我已经搜索并找不到以这种方式将 WITH 与 UPDATE 一起使用的任何示例,但我也没有看到任何表明它不应该工作的东西。这只是不受支持,还是我犯了一些愚蠢的错误?

而且,如果它不受支持,我是否应该将那个讨厌的长表达式复制到我在 UPDATE 子句中使用“newtz”的三个位置中的每一个中?或者有什么更好的方法来完成这个更新?

【问题讨论】:

  • 我开始意识到 WITH 子句创建一个临时视图,而不是一个标量变量。但即使将查询更改为创建并将其用作视图,当它到达 UPDATE 时它仍然会阻塞。看起来好像您不能将 WITH 与 UPDATE 一起使用(尽管文档似乎另有声明)。
  • newtz 不是字段名称,而是 CTE 的名称(在语法上类似于表别名)
  • @JoeStrout 更准确的说法是在 PostgreSQL 中它创建了一个临时的 materialized 视图。 CTE 术语总是会实现。 (顺便说一句,总是在问题中显示您的 PostgreSQL 版本)。

标签: postgresql sql-update common-table-expression


【解决方案1】:

错误:“更新”处或附近的语法错误
第 2 行:更新 cross_rental

此特定错误消息表明您使用的是 PostgreSQL 版本 9.0 或更早版本。 9.1 之前的两个主要版本具有 CTE 和 WITH,但不在数据修改查询的上下文中。 这出现在 9.1 中。请参阅 PostgreSQL 9.1 文档中的 7.8.2. Data-Modifying Statements in WITH

假设更新版本,CTE 必须用作具有行和列的表(而不是作为标量变量),因此应按照Richard Huxton's answer 中所述修复查询。

【讨论】:

  • 啊哈,我想就是这样。我确实使用的是 9.0 版。我无法在 9.1 中轻松对其进行测试,但我没有理由怀疑您并非绝对正确,因此我将其标记为已接受的答案。
【解决方案2】:

它是一个表(或者无论如何来自记录集源)。

WITH calculated AS (
    SELECT ....
)
UPDATE foo
SET bar = calculated.something
FROM calculated
WHERE ...

【讨论】:

    【解决方案3】:
    WITH (SELECT timezone FROM timezonebyzipcode WHERE zip=(SELECT zip_code FROM company WHERE id=company_id)) AS newtz
    

    你有别名和反向引用...

    【讨论】: