删除具有指定参数但在 Postgresql 中最新的所有行

Delete all rows with specified parameters but newest in Postgresql

我有一个散列-table:

CREATE TABLE hash_table ( hash_id bigserial, 
user_name varchar(80),
 hash varchar(80), 
exp_time bigint,
 PRIMARY KEY (hash_id));


INSERT INTO hash_table (hash_id, user_name, exp_time) VALUES
(1, 'one',   10),
(2, 'two',   20),
(3, 'three', 31),
(4, 'three', 32),
(5, 'three', 33),
(6, 'three', 33),
(7, 'three', 35),
(8, 'three', 36),
(9, 'two',   40),
(10, 'two',   50),
(11, 'one',   60),
(12, 'three', 70);

exp_time - 哈希的过期时间。 exp_time = now() + delta_time 行创建时

我需要一个结果:

(1, 'one',   10),
(2, 'two',   20),
(7, 'three', 35),
(8, 'three', 36),
(9, 'two',   40),
(10, 'two',   50),
(11, 'one',   60),
(12, 'three', 70);

它包含很多 user_name-hash 对。 user_name可能会重复很多时间。

如何删除指定的 user_name 中最新的所有行(几个,例如 10 个)?

我找到了 this 解决方案(对于 mySQL 但我希望它有效)但它删除了所有其他 user_names

DELETE FROM `hash_table`
WHERE user_name NOT IN (
  SELECT user_name
  FROM (
    SELECT user_name
    FROM `hash_table`
    ORDER BY exp_time DESC
    LIMIT 10 -- keep this many records
  )
);

您可以使用row_number根据exp_time降序对用户的行进行编号。然后从 table 中删除超过 10 个条目的用户行。

Fiddle with sample data

 delete from hash_table as h 
 using
 (
 SELECT user_name, exp_time,
 row_number() over(partition by user_name order by exp_time desc) as rn
 FROM hash_table
 ) as t
 where h.user_name = t.user_name and h.exp_time <= t.exp_time and t.rn > 10;

这将为每个 user_name:

保留 3 个最新记录
DELETE FROM hash_table h
USING
(
  SELECT
    user_name,
    exp_time,
    row_number() OVER (PARTITION BY user_name ORDER BY exp_time DESC) AS r
  FROM
    hash_table
) AS s
WHERE
  h.user_name = s.user_name
  AND h.exp_time<s.exp_time
  AND s.r=3
DELETE FROM hash_table WHERE hash_id NOT IN (SELECT hash_id FROM hash_table WHERE user_name = 'three' ORDER BY exp_time DESC LIMIT 3) AND user_name = 'three';

我自己的回答:查询只计算需要 user_name 的行,而不是所有 user_name 的行。