2011-04-06 45 views
3

我有一个嵌入Flash游戏的Drupal网站。PostgreSQL加入:删除一个表中的记录,但不是另一个

注册网站用户都在drupal_users上市表 - 在这里的人的名单,注册了一个多星期前:

# select uid, created from drupal_users where 
     to_timestamp(created) < (now() - interval '7 days') limit 5; 
uid | created 
------+------------ 
9903 | 1300257067 
9904 | 1300259929 
9750 | 1299858284 
9751 | 1299858603 
8083 | 1285514989 
(5 rows) 

闪存游戏用户另一个表列 - 在pref_users,并有 “DE” 的字符串前置到其ID:

# select id from pref_users where id like 'DE%' limit 5; 
    id 
-------- 
DE9054 
DE9055 
DE9056 
DE9057 
DE9058 
(5 rows) 

我想摆脱一个星期前在我的网站注册的(可能是垃圾邮件机器人)用户,但仍然没有玩过Flash游戏。即我想删除drupal_users记录,这些记录不存在于pref_users表中。

同时我不想做这样的事情:

# delete from drupal_users where 
    to_timestamp(created) < (now() - interval '7 days') and 
    'DE'||uid not in (select id from pref_users where id like 'DE%'); 

,因为我不知道,select语句上面有多大允许是(也许是有极限的我使用PostgreSQL 8.4.7和CentOS 5.5/64位在Drupal7之前,我使用phpBB3,有时候我看到这种SQL语句在删除phpBB3管理控制台中的旧论坛帖子时失败了。

所以我的问题是,如果上面的声明可以重写为some kind of SQL-join

回答

1

将删除重写为SQL连接是不可能的,AFAIK。 但是你为什么不喜欢

delete from drupal_users where 
to_timestamp(created) < (now() - interval '7 days') and 
'DE'||uid not in (select id from pref_users where id like 'DE%'); 

这句话的大小是静态的(你不产生任何这里动态SQL),所以这是一个非常有效的方法,而应该运行非常快(如果是这样的你关心的是什么)。

+0

因为我打了一些PostgreSQL的限制(不记得是哪一个,抱歉)具有类似的语句从“删除:

delete from drupal_users where dont_delete is null and to_timestamp(drupal_users.created) < (now() - interval '7 days'); 

与清理table1其中id在(从table2中选择id)“从phpBB3 ACP删除旧的论坛帖子时。 – 2011-04-06 09:57:53

+0

PostgreSQL有一个DELETE的扩展(非标准),你可以用USING指定另一个表,但我猜这在这里是不可能的(因为 - 如果我理解USING正确 - 它总是执行一个内部连接)。但你可能想自己检查一下。 – 2011-04-06 10:36:58

+0

好吧,你是否认为添加不同的(从pref_users选择ID,像'DE%'这样的ID)是一个好主意? – 2011-04-06 11:02:04

0

我重新在那里你说有一些PostgreSQL的极限场景:

create table t0 (id int primary key); 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "t0_pkey" for table "t0" 
CREATE TABLE 

create table t1 (id int primary key); 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "t1_pkey" for table "t1" 
CREATE TABLE 

insert into t0 (id) 
select * from generate_series(1, 100000, 2); 
INSERT 0 50000 

insert into t1 (id) 
select * from generate_series(2, 100000, 2); 
INSERT 0 50000 

select * from t0 order by id limit 3; 
id 
---- 
    1 
    3 
    5 
(3 rows) 

select * from t1 order by id limit 3; 
id 
---- 
    2 
    4 
    6 
(3 rows) 

现在我删除所有T0行中不存在T1(全部):

delete from t0 
where id not in (select id from t1); 

和它的作品

+0

谢谢你试试这个 – 2011-04-15 14:47:11

0

这里是另一种方式来做到这一点,使用EXISTS子查询:

delete from drupal_users D 
where to_timestamp(created) < (now() - interval '7 days') 
and not exists (select 1 from pref_users P where P.id = 'DE' || D.uid); 
3

使用NOT IN处理跨越有数百万条记录的表的联接时,我无法获得可接受的性能。 相反,我写了相当于:

alter table drupal_users add column dont_delete boolean; 

然后

update drupal_users set dont_delete = true from pref_users 
where 'DE'||drupal_users.uid = pref_users.id. 

这将停止尽快有效作为新drupal_users被创建,但因为你只是删除记录7天以上,这是好。 最后,验证您的记录和问题:

alter table drupal_users drop column dont_delete; 
+0

非常有帮助,谢谢! – 2012-05-10 12:37:41

相关问题