如何在PostgreSQL中的单个SQL语句中更新一个字段并获取整个实体?

时间:2013-12-15 03:33:33

标签: sql postgresql

这是我的问题:

UPDATE invoices SET
   version = o.version + 1
  ,modified = CURRENT_TIMESTAMP
  ,business_no = $3::numeric
FROM invoices o
LEFT JOIN reps ON reps.rep_id = o.rep_id
LEFT JOIN terms ON terms.terms_id = o.terms_id
LEFT JOIN shipvia ON shipvia.ship_via_id = o.ship_via_id
WHERE o.id = $1::int AND CASE WHEN $2::numeric IS NULL THEN o.business_no IS NULL ELSE o.business_no = $2::numeric END
RETURNING o.id, o.version, o.business_no, ..., terms, rep, ship_via

它应该执行以下操作:

  1. 按ID($ 1)找到所需的发票,并在business_no字段($ 2)中设置期望值,将business_no字段设置为新值($ 3)
  2. 将版本字段提前一个。
  3. 更新后,返回所有发票的字段。
  4. 不幸的是,它没有按预期工作。它不是只更新一张发票而是返回新版本,而是:

    1. 更新所有发票
    2. 返回重复N次的发票的更新前版本,其中N是发票的总数。
    3. 我理解我的查询错误,我只是无法理解为什么以及如何解决它。

1 个答案:

答案 0 :(得分:0)

您的问题是您在FROM列表中指定发票而不将其绑定到UPDATEd的发票表。 manual警告说。所以一个简单的解决方法如下:

   UPDATE invoices i
      SET version = i.version + 1,
          modified = CURRENT_TIMESTAMP,
          business_no = $3::numeric
     FROM           invoices o
          LEFT JOIN reps ON reps.rep_id = o.rep_id
          LEFT JOIN terms ON terms.terms_id = o.terms_id
          LEFT JOIN shipvia ON shipvia.ship_via_id = o.ship_via_id
    WHERE o.id = i.id
      AND o.id = $1::int
      AND (   (o.business_no IS NULL AND $2 IS NULL)
           OR (o.business_no = $2::numeric))
RETURNING i.id, i.version, i.business_no, i.modified, reps.name, terms.data, shipvia.who

我有SQLFiddle显示参数的硬编码值。

但是,由于您似乎只是为了RETURNING子句而加入辅助表,您可能想要重新组织整个事情:

WITH o AS (
     UPDATE invoices
        SET version = version + 1,
            modified = CURRENT_TIMESTAMP,
            business_no = $3::numeric
      WHERE id = $1::int
        AND (   (business_no IS NULL AND $2 IS NULL)
             OR (business_no = $2::numeric))
  RETURNING *
) SELECT o.id, o.version, o.business_no, o.modified, reps.name, terms.data, shipvia.who
    FROM           o
         LEFT JOIN reps ON reps.rep_id = o.rep_id
         LEFT JOIN terms ON terms.terms_id = o.terms_id
         LEFT JOIN shipvia ON shipvia.ship_via_id = o.ship_via_id;

并更新SQLFiddle以显示第二个版本。我不能说在这种情况下它是否更好,但它是一种可能有益的替代技术。