简体   繁体   中英

Delete all rows with specified parameters but newest in Postgresql

I have a hash-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 - expiration time of hash. exp_time = now() + delta_time when the row creates

I need a result:

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

It contains a lot of user_name-hash pairs. user_name may dublicate a lot of time.

How to delete all rows but (several, eg 10) newest of specified user_name ?

I found this solution (for mySQL but I hope it works) but it removes all other 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
  )
);

This will keep 3 newest records for each user_name:

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

You can use row_number to number rows of a user based on exp_time in the descending order. And then delete user rows from the table who have more than 10 entries.

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;
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计算行。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM