从 sql 中删除行号大于指定的每个组的寄存器

Delete registers with rownumber greater than specified for each group got from sql

我有 table 个人在博客上发表评论。我需要在 table 中为每个人留下最后 10 条评论,并删除较旧的评论。假设列是:

我知道如何处理多个查询,但不是只处理一个查询(允许任何子查询)和任何数据库

与:

select personId from PeopleComments 
group by personId
having count(*) >10 

我会获取评论超过 10 条的人员 ID,但我不知道如何从那里获取评论 ID 并将其删除

谢谢!

您需要一个计算以下评论的相关子查询:

delete from peoplecomments pc
where
(
  select count(*)
  from peoplecomments pc2
  where pc2.personid = pc.personid
  and pc2.datefromcomment > pc.datefromcomment
) >= 10; -- at least 10 newer comments for the person

顺便说一句:虽然看起来我们可以简单地对行进行编号并通过

进行相应删除
delete from
(
  select
    pc.*, row_number() over (partition by personid order by datefromcomment desc) as rn
  from peoplecomments pc
)
where rn > 10;

Oracle 不允许这样做并给了我们 ORA-01732: data manipulation operation not legal on this view.

在我的另一个回答中,DBMS 必须为 table 中的每一行查找并计算行数。这可能很慢。最好找到我们要保留的所有行一次,然后删除其他行。因此这个额外的答案。

从版本 12c 开始,以下适用于 Oracle:

delete from peoplecomments
where rowid not in
(
  select rowid
  from peoplecomments
  order by row_number() over (partition by personid order by datefromcomment desc)
  fetch first 10 rows with ties
);

除了 ROWID 这是标准的 SQL。

在其他支持 window 函数和 FETCH WITH TIES 的 DBMS 中:

  • 如果您的 table 有一个单列主键,您将用它替换 ROWID
  • 如果您的 table 有复合主键,您可以使用 where (col1, col2) not in (select col1, col2 ...),前提是您的 DBMS 支持此语法。