我想删除最近插入的最多“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
???
如果您的表没有任何序列 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
);
您可以调整使用 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>;
这可以确保准确删除行,即使有联系。
如果没有候选键可以排序,可以随时使用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
顺序将是或多或少随机的)
我使用pgAdmin4。如果没有主键,pgAdmin4 不允许编辑表。
它的工作原理: 从 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"。