代码之家  ›  专栏  ›  技术社区  ›  Robin Barnes

如何基于count-sql(postgres)进行更新

  •  2
  • Robin Barnes  · 技术社区  · 17 年前

    我有一张表,我们称之为“条目”,它看起来像这样(简化):

    id [pk]
    user_id [fk]
    created [date]
    processed [boolean, default false]
    

    我想创建一个更新查询,它将所有条目上的已处理标志设置为true,每个用户的最近3个条目除外(根据所创建的列最新)。因此,对于以下条目:

    1,456,2009-06-01,false
    2,456,2009-05-01,false
    3,456,2009-04-01,false
    4,456,2009-03-01,false
    

    只有条目4才会将其处理标志更改为true。

    有人知道我怎么做吗?

    2 回复  |  直到 17 年前
        1
  •  4
  •   Steve Kass    17 年前

    我不知道Postgres,但这是标准的SQL,可能对您有用。

    update entries set
      processed = true
    where (
      select count(*)
      from entries as E
      where E.user_id = entries.user_id
      and E.created > entries.created
    ) >= 3
    

    换言之,如果在以后的日期同一用户的ID有三个或更多条目,请将“已处理”列更新为“真”。我假设[创建的]列对于给定的用户ID是唯一的。如果不是,您需要一个额外的条件来确定您所说的“最新”是什么意思。

    在SQL Server中,您可以这样做,这样更容易执行,而且执行效率可能更高:

    with T(id, user_id, created, processed, rk) as (
      select
        id, user_id, created, processed,
        row_number() over (
          partition by user_id
          order by created desc, id
        )
      from entries
    )
      update T set
        processed = true
      where rk > 3;
    

    更新CTE是一项非标准功能,并非所有数据库系统都支持行号。

        2
  •  4
  •   user80168    17 年前

    首先,让我们从列出所有要更新行的查询开始:

    select e.id
    from entries as e
    where (
        select count(*)
        from entries as e2
        where e2.user_id = e.user_id
            and e2.created > e.created
    ) > 2
    

    这将列出所有记录的ID,这些记录有两个以上的这样的记录,用户ID相同,但创建的记录晚于要返回的行中创建的记录。

    也就是说,它将列出除每个用户最后3条以外的所有记录。

    现在,我们可以:

    update entries as e
    set processed = true
    where (
        select count(*)
        from entries as e2
        where e2.user_id = e.user_id
            and e2.created > e.created
    ) > 2;
    

    有一件事是想的——它可能很慢。在这种情况下,您最好使用自定义聚合,或者(如果您使用的是8.4)窗口函数。