【问题标题】:Updating a column with the results of a query in PostgreSQL使用 PostgreSQL 中的查询结果更新列
【发布时间】:2012-11-25 21:58:59
【问题描述】:

我在 PostgreSQL 9.2 中有下表,其中包含时间戳:

gid [PK] (bigserial), timestamp_mes (timestamp without time zone), time_diff (interval)
1、2012-01-23 11:03:40,空
2、2012-01-23 11:03:42,空
3、2012-01-23 11:03:44,空

我添加了一个间隔列 (time_diff),并希望用此查询产生的时差值填充它:

SELECT timestamp_mes - lag(timestamp_mes, 1) 
over (order by timestamp_mes) as diff
from gc_entretien.trace order by timestamp_mes

我尝试了以下查询来更新 time_diff 列,但没有成功:

UPDATE gc_entretien.trace set time_diff = 
(SELECT trace.timestamp_mes - lag(trace.timestamp_mes, 1) 
over (order by trace.timestamp_mes) 
from gc_entretien.trace order by timestamp_mes);

这会导致错误:

错误:用作表达式的子查询返回多行

我应该如何使用时差查询产生的值更新 time_diff 列?

【问题讨论】:

  • 不确定您的应用程序的逻辑,但选择可能返回更多行,这在分配到单列时会导致错误(就像您在 UPDATE 中所做的那样)...如果结果在在您的SELECT 返回的第一行,使用LIMIT 1 使分配成为可能。无论如何,选择似乎没有正确设计。
  • @KamilŠrot - 这有问题;因为子查询(当前)不相关,LIMIT 1 将只返回顶行,句点,而不是与当前行有任何关系的。
  • @Clockwork-Muse 对,这就是为什么我说它的查询设计不正确。首先@jatobat 需要创建一个查询返回恰好一个值(根据应用程序逻辑他需要的那个),然后将其作为子查询放入UPDATE 查询......通常的情况是使用表中的一些标识符/值(相应的行)在子查询中被更新为子查询WHERE 子句中的条件。但坦白说:我不懂应用程序的逻辑,甚至不想理解它:-)

标签: sql database postgresql sql-update postgresql-9.2


【解决方案1】:

您不能在 UPDATE 中直接使用窗口函数,因此您需要在子 SELECT 中使用它——您已经这样做了。但是,您尝试在 UPDATE 中使用该子 SELECT 的方式不是有效的语法。您需要将 sub-SELECT 放在更新的 FROM 子句中,如 Postgres 文档所述:

http://www.postgresql.org/docs/9.2/static/sql-update.html

你想要做的正确语法是:

UPDATE gc_entretien.trace t
SET time_diff = subquery.diff
FROM (SELECT {{SomeUniqueId}}, 
             timestamp_mes - lag(timestamp_mes, 1) over (order by timestamp_mes) as diff
      FROM gc_entretien.trace order by timestamp_mes) AS subquery
WHERE t.{{SomeUniqueId}} = subquery.{{SomeUniqueId}}

显然,您需要用我写过{{SomeUniqueId}}的行所具有的某个唯一ID 的列名替换

【讨论】:

    【解决方案2】:

    类似这样的:

    with new_values as (
       SELECT gid, 
              timestamp_mes - lag(timestamp_mes, 1) over (order by timestamp_mes) as diff
       from gc_entretien.trace 
    )
    update gc_entretien.trace as tr
      set time_diff = nv.diff
    from new_values nv
    where nv.gid = tr.gid;
    

    【讨论】:

    • +1。这对我来说是正确的,并以 4 分钟的优势击败了我。直到现在才知道WITH... AS... 的存在。凉爽的。 :)
    • @MarkAmery:这就是所谓的“公用表表达式”,从 9.1 开始,它也可以用于 DML 语句(在此之前它只能用于普通的 SELECT 语句 - 包括递归查询)跨度>
    • 如果您在 T-SQL 中执行此操作,那么您似乎无法为更新表设置别名。如果您显式使用表名(在这种情况下而不是 tr),它会起作用。
    • @SpencerKershaw:嗯,这个问题被标记为postgresql,所以很明显这个答案不适用于 SQL Server。
    • 您的答案非常有用,尽管对于一般的 SQL 来说,这正是我想要的。我只是想其他人可能会遇到和我一样的经历。
    【解决方案3】:

    实际上您收到此错误是因为您的子查询返回多个结果,

    我无法理解您的问题,

    我给你举个例子来解决,

    update table t1 set time_diff= select *your_operation* from table t2 where t1.id=t2.id
    

    这里 :-your_operation 表示查找时差的逻辑,

    【讨论】:

    • 是的,这是他需要做的一般形式...也许填写查询的其余部分?
    • 这个答案对我有 PostgreSQL 9.0.1 的问题有用。谢谢。
    猜你喜欢
    • 2021-01-19
    • 2023-01-22
    • 1970-01-01
    • 2020-08-28
    • 2016-08-22
    • 2019-02-25
    • 1970-01-01
    • 2015-09-04
    • 2021-11-12
    相关资源
    最近更新 更多