2011-04-06 61 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

相關問題