如何根据计数进行更新 - SQL(postgres)

时间:2009-08-10 12:47:07

标签: sql postgresql

我有一张桌子,我们称之为'条目',看起来像这样(简化):

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

我想创建一个UPDATE查询,它将在所有条目上将处理后的标志设置为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 个答案:

答案 0 :(得分:4)

我不知道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

换句话说,只要在以后的日期有相同user_id的三个或更多条目,就将已处理列更新为true。我假设[created]列对于给定的user_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是一项非标准功能,并非所有数据库系统都支持row_number。

答案 1 :(得分:4)

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

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,这些记录有超过2条这样的记录,即user_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)窗口函数。