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

Mysql SQL删除时间戳早于(现在-x天)的所有行,但保留最近的n条记录除外,mysql,sql,Mysql,Sql,如果我有下表,我需要删除所有比现在早-x天的记录,但这些记录不在最近的n个记录中 具体示例:用户不能在90天内重复使用密码,也不能重复使用最后10个密码。如果我每90天更改一次密码,我仍然无法重复使用密码进行10次更改 CREATE TABLE PASSWORD_HISTORY ( ID BIGINT NOT NULL AUTO_INCREMENT, USER_NAME VARCHAR(255) NOT NULL, PASS

如果我有下表,我需要删除所有比现在早-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;

这将只删除ID最低的行,如果这些行属于具有10条以上记录的用户名,并且这些行的创建时间戳超过90天。当然,您应该使用SELECT*来代替DELETE来运行它,以确保它提供了您想要的内容。此外,我将使用Begin事务运行;并准备回滚事务;如果删除时出现问题。

如果我理解正确,您希望删除最近的记录超过90天且密码不在最近90天内的记录。我不知道你为什么要删除这些。您可以在查询数据时强制执行这些规则,而不是在数据本身中。如果您愿意,您可以轻松地将规则更改为120天

在任何情况下,如果只为每个用户枚举密码,这将简单得多。但事实并非如此,MySQL也不支持行号。这建议使用变量来枚举结果。由于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)

你能解释一下为什么你有一个更新的时间戳列吗?你发布了一个密码历史记录表,我猜你是用它来存储用户一段时间以来使用过的不同密码的。你是在问如果某个特定用户的行超过x天并且不是最近10天,如何从该表中删除这些行?我不需要更新的\u时间戳…习惯的力量包括在内;我怀疑我会在代码完成之前放弃。按用户名列出的最后n条记录或表中的总共n条记录按用户名列出的最后n条记录我留给您90天的时间。如果您同意结果,则执行删除操作,其中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()))
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)