Postgres:删除没有主键的行 order by

问题描述 投票:0回答:4

我想删除最近插入的最多“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

???

sql postgresql sql-delete
4个回答
4
投票

如果您的表没有任何序列 ID(例如,如果存在现有的多列主键),您仍然可以使用

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
投票

您可以调整使用 ids 找到的代码:

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>;

这可以确保准确删除行,即使有联系。


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
顺序将是或多或少随机的)


0
投票

我使用pgAdmin4。如果没有主键,pgAdmin4 不允许编辑表。

enter image description here

它的工作原理: 从 users_roles 中删除,其中“User_id”= 2; DELETE FROM users_roles WHERE "User_id" IN (SELECT "User_id" FROM users_roles WHERE "User_id" = 2);

但这会抛出错误 从 users_roles 中删除,其中“User_id”= 2;

错误:列“user_id”不存在 第 1 行:从 users_roles 中删除,其中 User_id = 2; 提示:可能有意引用“users_roles.User_id”列。 SQL状态:42703 角色:31

在 PostgreSQL 中,不带引号的名称不区分大小写。因此 SELECT * FROM hello 和 SELECT * FROM HELLO 是等价的。

但是,带引号的名称区分大小写。 SELECT * FROM "hello" 不等于 SELECT * FROM "HELLO"。

© www.soinside.com 2019 - 2024. All rights reserved.