Keep only last 5 search results of user in a table

2019-02-19 10:21发布

问题:

I need to keep the last 5 search results of a user in a table.
I wrote a script to remove other rows, but it didn't work:

DELETE FROM         
    SELECT
        ROW_NUMBER () OVER (ORDER BY search_time DESC) AS row_number;
    FROM
        history_user
    WHERE
        user_id = 188
WHERE row_number>5

What did I do wrong?

回答1:

Proper syntax as detailed in the manual:

DELETE FROM history_user h
USING (
    SELECT pk_id, row_number() OVER (ORDER BY search_time DESC) AS rn;
    FROM   history_user
    WHERE  user_id = 188
    ) sub
WHERE sub.rn > 5
AND   h.pk_id = sub.pk_id;

Where pk_id is any (combination of) column(s) that is unique. Might be user_id, search_time in your case - or, more conveniently, a surrogate primary key.

For just a single user_id you can simplify to:

DELETE FROM history_user h
USING (
    SELECT pk_id
    FROM   history_user
    WHERE  user_id = 188
    ORDER  BY search_time DESC
    OFFSET 5
    ) sub
WHERE h.pk_id = sub.pk_id;

On the other hand, to deal with multiple users at once, you need to add PARTITION BY to your window function:

DELETE FROM history_user h
USING (
    SELECT pk_id, row_number() OVER (PARTITION BY user_id
                                     ORDER BY search_time DESC) AS rn;
    FROM   history_user
    ) sub
WHERE sub.rn > 5
AND   h.pk_id = sub.pk_id;