Postgres:删除没有主键的行顺序

时间:2017-10-01 14:01:17

标签: sql postgresql sql-delete

我想删除最近的插入到" n"行。

例如:

DELETE FROM users 
WHERE user_id = %s AND group_id = %s 
ORDER BY message_date DESC

我理解它是一个语法错误并在网上搜索我发现许多stackoverflow答案告诉使用像

这样的表单
DELETE FROM users 
WHERE id IN (SELECT id ....)

不幸的是,我在该表上没有主键,它们只是没有自动增量的插入。

我该怎么做?

也许我应该喜欢

WITH t AS 
(
    SELECT * 
    FROM users 
    WHERE user_id = %s AND group_id = %s 
    ORDER BY message_date DESC
) 
DELETE FROM t

???

3 个答案:

答案 0 :(得分:3)

如果您的表没有任何序列号(例如,如果存在现有的多列主键),您仍然可以使用IN过滤要删除的行:

DELETE FROM table_name
WHERE (key1, key2) IN (
    SELECT key1, key2 FROM table_name ORDER BY date DESC LIMIT 2
);

根据您的具体情况,您可以使用:

DELETE FROM users 
WHERE (user_id, group_id) IN (
    SELECT user_id, group_id FROM users
    WHERE user_id = %s AND group_id = %s
    ORDER BY message_date DESC
);

答案 1 :(得分:1)

您可以使用ID修改您找到的代码:

DELETE users u
    WHERE u.user_id = %s AND u.group_id = %s AND
          u.message_date IN (SELECT u2.message_date
                             FROM users u2
                             WHERE u2.user_id = u.user_id AND
                                   u2.group_id = u.group_id
                             ORDER BY u2.message_date DESC
                             LIMIT <n>
                            );

我希望您从中了解到有用的主键可以在数据库中使用。

注意:如果数据库中存在联系,则可以删除多行。

编辑:

让我补充一点,我更倾向于将其作为:

DELETE users u
    FROM (SELECT u2.*,
                 ROW_NUMBER() OVER (PARTITION BY user_id, group_id ORDER BY message_date DESC) as seqnum
          FROM users u2
         ) u2
         ON u2.user_id = u.user_id AND u2.group_id = u.group_id AND
            u2.message_date = u.message_date
     WHERE u.user_id = %s AND u.group_id = %s AND
           seqnum <= <n>;

这可确保删除准确的行,即使是绑定。

答案 2 :(得分:1)

如果订购时没有候选键,您可以随时使用ctid :(保证唯一)

DELETE FROM one
WHERE EXISTS (
        SELECT *
        FROM one x
        WHERE x.oneseq <= 3 -- whatever condition
        AND x.ctid = one.ctid
        ORDER BY x.ctid
        LIMIT 3 -- number of rows you want todelete
        );

这也适用于row_number() OVER (PARTITION BY...ORDER BY ctid) as rn。 (这当然是荒谬的,因为ctid订单或多或少随机