繁体   English   中英

SQL删除时间戳记早于(现在-x天)的所有行,但保留最新的n条记录

[英]SQL to delete all rows with timestamp older than (now - x days) except keep the most recent n records

如果有下表,则需要删除所有早于(现在-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;
-- 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
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()))

仅当ID最低的行属于具有10条以上记录的用户名并且这些行的Created_TimeStamp超过90天时,才会删除该行。 当然,您应该使用SELECT *代替DELETE来运行它,以确保它能为您提供所需的内容。 另外,我将使用“ Begin Transaction;来运行Begin Transaction; 并准备Rollback Transaction; 如果删除时变酸。

如果我理解正确,则要删除最近记录超过90天且密码不在最近90天的记录。 我不确定为什么您实际上需要删除它们。 您可以在查询数据时而不是在数据本身中强加这些规则。 然后,您可以根据需要轻松地将规则更改为120天。

在任何情况下,如果只是为每个用户枚举密码,这将更加简单。 但是它们不是,MySQL不支持row_number() 这建议使用变量来枚举结果。 由于MySQL的规则,这需要一个子查询和joindelete 其余只是基本的条件逻辑:

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM