使用WITH子句即时更新创建的记录

时间:2017-06-27 13:21:01

标签: sql postgresql common-table-expression

我尝试更新在同一查询中使用WITH子句创建的记录,如下所示:

WITH
  document AS (
    INSERT INTO documents (name) VALUES ($1)
    RETURNING *
  )
UPDATE documents
SET documents.description = $2
FROM document
WHERE documents.id = document.id;

我也试过

WITH
  new_document AS (
    INSERT INTO documents (name) VALUES ($1)
    RETURNING *
  ),
  updated_document AS (
    UPDATE documents
    SET documents.description = $2
    WHERE documents.id = (SELECT id FROM new_document)
    RETURNING *
  )
SELECT * FROM updated_document;

但它似乎不起作用。我知道这个例子很傻,因为我可以同时创建一个同时包含名称和描述的新文档,但我需要它在我的应用程序中这样做;这个例子是故意简化的。

修改

我创建了一个带有真实世界示例的Gist。我知道我可以将更新document_id的逻辑嵌入到函数体中。我猜。但是假设urls不仅可以对应于文档,还可以对应于许多其他实体,例如文档,故事,用户,文章,标签等等,将对所有这些实体的引用嵌入到函数体中是繁琐,因为(由于函数重载)我将不得不创建像get_url_for_document(id uuid)get_url_for_story(id uuid)get_url_for_user(id uuid)等函数。

2 个答案:

答案 0 :(得分:2)

在两个单独的语句中或在函数内部执行。由于实施WITH的方式,你不能像你尝试的那样去做。

来自documentation

  

WITH中的子语句彼此同时执行   并与主要查询。因此,在使用数据修改时   WITH中的语句,实际指定更新的顺序   发生是不可预测的。所有语句都以相同的方式执行   快照(见第13章),所以他们不能"看"彼此的影响   在目标表上。

答案 1 :(得分:1)

你想要做的事是不可能的。

来自手册:https://www.postgresql.org/docs/current/static/queries-with.html

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM products;

外部SELECT将在UPDATE操作之前返回原始价格,而在

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM t;

外部SELECT将返回更新的数据。

在您给出的示例中,您的更新尝试对不存在的行执行操作。使用WITH子句无法修复此问题。

我很想知道为什么你的代码强迫你这样做。