mysql表的sql公式

91zkwejq  于 2021-06-15  发布在  Mysql
关注(0)|答案(3)|浏览(299)

您好–我有一个db表(mysql版本5.6.41-84.1-log),它有大约92000个条目,其中列用于:
id(增量唯一id)
后置类型(不重要)
post\u id(不重要,但显示与另一个表的关系)
用户id(不重要)
投票(不重要)
ip(ip地址,即123.123.123.123)
投票(以gmt为单位的日期戳,即2018-12-03 04:50:05)
我最近举办了一个比赛,我们有一个规则,没有一个ip可以投票超过60次,每天。因此,现在我需要运行一个自定义sql公式,该公式应用以下规则:
对于每个ip地址,如果每天有>60行,则删除这些额外的行。
谢谢你的帮助!

lndjwyie

lndjwyie1#

这是一个复杂的问题,我认为如果没有实际的表格和数据,很难给出100%肯定的答案。
不过,让我试着描述一下逻辑,并一步一步地构建查询,这样您就可以使用它并可能修复潜在的错误。
1) 我们首先选择所有ip地址,张贴超过60票的一天。为此,我们使用 group by 在投票日和ip地址,结合 having 条款

select date(voted), ip_adress
from table 
group by date(voted), ip_adress 
having count(*) > 60

2) 然后,我们回到表中,选择对应于每个投票日/ip地址对的前60个ID。 id 是一个自动递增的字段,所以我们只使用这个字段进行排序,然后使用mysql limit 指令

select id, ip_adress, date(voted) as day_voted
    from table 
    where ip_adress, date(voted) in (
        select date(voted), ip_adress 
        from table 
        group by date(voted), ip_adress 
        having count(*) > 60
    ) 
    order by id
    limit 60

3) 最后,我们再次返回表并搜索ip地址和投票日期属于上述列表,但其id大于该列表的最大id的所有id。这是通过 join 需要一个 group by 条款。

select t1.id 
from 
    table t1
    join (      
        select id, ip_adress, date(voted) as day_voted 
        from table 
        where ip_adress, date(voted) in (
            select date(voted), ip_adress 
            from table
            group by date(voted), ip_adress
            having count(*) > 60
        )
        order by id
        limit 60
    ) t2 
        on t1.ip_adress = t2.ip_adress 
        and date(t1.voted) = t2.day_voted and t1.id > max(t2.id)
group by t1.id

它应该返回我们需要删除的所有ID的列表。在你更进一步之前测试一下。
4) 最后一步是删除这些ID。mysql中存在一些限制,使得 delete 子查询条件很难实现。有关技术背景的更多信息,请参见下面的so问题。您可以使用一个临时表来存储所选的id,也可以尝试通过 Package 子查询并对其使用别名来胜过mysql。让我们试试第二种选择:

delete t.* from table t where id in ( select id from (
    select t1.id 
    from 
        table t1
        join (      
            select id, ip_adress, date(voted) as day_voted 
            from table 
            where ip_adress, date(voted) in (
                select date(voted), ip_adress
                from table 
                group by date(voted), ip_adress
                having count(*) > 60
            )
            order by id
            limit 60
        ) t2 
            on t1.ip_adress = t2.ip_adress
            and date(t1.voted) = t2.day_voted
            and t1.id > max(t2.id)
    group by t1.id
) x );

希望这有帮助!

nmpmafwu

nmpmafwu2#

有人帮我写了下面的问题,解决了我的问题。

SET SQL_SAFE_UPDATES = 0;
create table temp( SELECT id, ip, voted
    FROM
        (SELECT id, ip, voted,
            @ip_rank := IF(@current_ip = ip, @ip_rank + 1, 1) AS ip_rank,
            @current_ip := ip
        FROM `table_name` where ip in (SELECT ip from `table_name` group by date(voted),ip having count(*) >60)
        ORDER BY ip, voted desc
        ) ranked
    WHERE ip_rank <= 2);
DELETE FROM `table_name`
WHERE id not in (select id from temp) and ip in (select ip from temp);
drop table temp;
r7s23pms

r7s23pms3#

您可以通过极大地简化示例数据,并对8.0之前的mysql版本使用行数模拟,或对8.0或更高版本使用窗口函数来实现这一点。在下面的示例中,我假设您不在版本8或更高版本上

drop table if exists t;
create table t(id int auto_increment primary key,ip varchar(2));
insert into t (ip) values
(1),(1),(3),(3),
(2),
(3),(3),(1),(2);

delete t1 from t t1 join
(
select id,rownumber from
(
select t.*,
         if(ip <> @p,@r:=1,@r:=@r+1) rownumber,
         @p:=ip p
from t
cross join (select @r:=0,@p:=0) r
order by ip,id
)s
where rownumber > 2
) a on a.id = t1.id;

进进出出子查询s为每个ip分配一个行号,然后子查询a选择行号>2,外部多表delete从t中删除,并连接到a以给出

+----+------+
| id | ip   |
+----+------+
|  1 | 1    |
|  2 | 1    |
|  3 | 3    |
|  4 | 3    |
|  5 | 2    |
|  9 | 2    |
+----+------+
6 rows in set (0.00 sec)

相关问题