2015-06-21 86 views
2

如果我有下表,我需要刪除所有比(現在 - x天)更早的記錄,但不是在最近的n個記錄中。SQL刪除所有行的時間戳比(現在 - x天)要早,除了保留最近的n條記錄

具體的例子:用戶不能在90天內重複使用的密碼可能不會再使用過去的10個密碼。如果我每90天更換一次密碼,我仍然無法重複使用密碼進行10次更改。

CREATE TABLE PASSWORD_HISTORY (
      ID BIGINT NOT NULL AUTO_INCREMENT, 
      USER_NAME VARCHAR(255) NOT NULL, 
      PASSWORD VARCHAR(255) NOT NULL, 
      SALT VARCHAR(255), 
      CREATED_TIMESTAMP BIGINT NOT NULL, 
      UPDATED_TIMESTAMP BIGINT NOT NULL, 
      TENANT_ID INTEGER DEFAULT -1234, 
      PRIMARY KEY (ID) 
)ENGINE INNODB; 
+0

u能解釋爲什麼你有一個UPDATED_TIMESTAMP列 – Drew

+0

你貼PASSWORD_HISTORY表,我猜你是用來存儲不同的密碼用戶有一段時間。你問如何從這個表中刪除行,如果它們大於X天,並且不在特定用戶的最近10行中? – DiscipleMichael

+0

我不需要更新時間戳...包括習慣的武力;我懷疑我會在代碼完成之前放棄。 –

回答

1
-- drop table password_history; 
create table password_history 
(
id bigint null auto_increment primary key, 
user_name varchar(255) not null, 
created_timestamp bigint not null 
); 

-- delete from password_history where id>0; -- safe mode sometimes barfs 
insert password_history (user_name,created_timestamp) values ('fred',100); 
insert password_history (user_name,created_timestamp) values ('fred',200); 
insert password_history (user_name,created_timestamp) values ('fred',300); 
insert password_history (user_name,created_timestamp) values ('fred',400); 
insert password_history (user_name,created_timestamp) values ('fred',401); 
insert password_history (user_name,created_timestamp) values ('fred',402); 
insert password_history (user_name,created_timestamp) values ('fred',403); 
insert password_history (user_name,created_timestamp) values ('fred',404); 
insert password_history (user_name,created_timestamp) values ('fred',405); 
insert password_history (user_name,created_timestamp) values ('fred',406); 
insert password_history (user_name,created_timestamp) values ('fred',407); 
insert password_history (user_name,created_timestamp) values ('fred',500); 
insert password_history (user_name,created_timestamp) values ('fred',555); 

insert password_history (user_name,created_timestamp) values ('fred',unix_timestamp(now())); 
insert password_history (user_name,created_timestamp) values ('stan',unix_timestamp(now())); 

alter table password_history add deleteMe int; 

select * from password_history; 

-- variables n and d 
-- n=10, users last 10 records 
-- d=90, last 90 days 
-- rows where password created more than 90 days ago (replace 90 below as desired) 
select * from password_history 
where unix_timestamp(now()) - created_timestamp>(60*60*24*90) 
order by id desc 

-- update password_history set deleteMe=1 where id>0; -- safe mode sometimes barfs 

-- update password_history set deleteMe=null where id>0; -- safe mode sometimes barfs 

update password_history 
join 
(
select ph.id,ph.user_name,ph.created_timestamp 
from password_history ph 
join 
(
select ph.id,ph.user_name,ph.created_timestamp 
from password_history ph 
join 
(
select user_name,max(id),max(created_timestamp),count(*) as theCount 
from password_history xx 
group by user_name 
having theCount>10 
) inR2 
on ph.user_name=inR2.user_name 
order by ph.user_name,ph.created_timestamp desc 
limit 10 
) inR1 
on ph.id=inR1.id 
) bigThing 
on password_history.id=bigThing.id 
set deleteMe='1' 
where password_history.id>0 -- this gets rid of the safe mode barfing 

update password_history 
join 
(
select user_name from password_history p2 where p2.deleteMe=1 
) phMany 
on password_history.user_name=phMany.user_name 
set deleteMe=2 
where password_history.deleteMe is null 

-- select * from password_history order by user_name,created_timestamp desc; 

-- look at the ones with deleteMe=2 
+0

我給你留下90天的方面。如果您同意結果,那麼執行delete where deleteMe = 2 ...和alter table drop the column – Drew

1
DELETE 
FROM PASSWORD_HISTORY 
Where PASSWORD_HISTORY.ID Not IN 

(
    SELECT ID FROM(SELECT pass1.[USER_NAME], Count(*) num, pass1.ID 
    FROM Password_History pass1 JOIN Password_History pass2 
     ON pass1.[USER_NAME] = pass2.[USER_NAME] AND pass1.ID <= pass2.ID 
    Group BY pass1.[USER_NAME], pass1.ID 
    Having Count(*) <= 10 

) a 

) 
AND CREATED_TIMESTAMP <= Convert(int, DATEADD(day, -90, GetDate())) 

這如果這些行屬於一個用戶名超過10個記錄和那些行有超過90天前Created_TimeStamp只會刪除具有最低ID的行。當然,你應該用SELECT *來代替DELETE來確保它給你你想要的東西。此外,我會運行一個Begin Transaction;,並準備好Rollback Transaction;,如果它在刪除時變酸。

1

如果我理解正確,您想要刪除最近記錄超過90天並且其密碼不在最近90天內的記錄。我不知道爲什麼你真的需要刪除這些。當你查詢數據時,你可以施加這些規則,而不是數據本身。然後,如果你喜歡,你可以輕鬆地將規則更改爲120天。

在任何情況下,如果僅爲每位用戶列舉密碼,這將會簡單得多。但他們不是,MySQL不支持row_number()。這表明使用變量來枚舉結果。由於MySQL的規則,這需要子查詢和delete中的join。剩下的只是基本條件邏輯:

delete ph 
    from password_history ph join 
     (select ph2.*, 
       (@rn := if(@u = user_name, @rn + 1, 
          if(@u := user_name, 1, 1) 
          ) 
       ) as seqnum 
      from password_history ph2 cross join 
       (select @rn := 0, @u := '') params 
      order by user_name, created_timestamp desc 
     ) ph2 
     on ph2.id = ph.id 
    where ph2.seqnum > 10 and 
      ph.created_timestamp <= date_sub(curdate(), interval 90 day) 
相關問題