Php 在mySQL中基于COUNT()值限制分组
我正在将事件记录到一个mySQL数据库中,并希望获得前3个事件,以便进行监视 我的表事件日志如下所示:Php 在mySQL中基于COUNT()值限制分组,php,mysql,sql,rdbms,Php,Mysql,Sql,Rdbms,我正在将事件记录到一个mySQL数据库中,并希望获得前3个事件,以便进行监视 我的表事件日志如下所示: +----+------------------+---------------------+ | id | eventname | eventdate | +----+------------------+---------------------+ | 0 | machine1.started | 2016-09-04 19:22:23 | | 1 |
+----+------------------+---------------------+
| id | eventname | eventdate |
+----+------------------+---------------------+
| 0 | machine1.started | 2016-09-04 19:22:23 |
| 1 | machine2.reboot | 2016-09-04 20:23:11 |
| 2 | machine1.stopped | 2016-09-04 20:24:12 |
| 3 | machine1.started | 2016-09-04 20:25:12 |
| 4 | machine1.stopped | 2016-09-04 23:23:16 |
| 5 | machine0.started | 2016-09-04 23:24:00 |
| 6 | machine1.started | 2016-09-04 23:24:16 |
| 7 | machine3.started | 2016-09-04 23:25:00 |
| 8 | machine4.started | 2016-09-04 23:26:00 |
| 9 | cluster.alive | 2016-09-04 23:30:00 |
| 10 | cluster.alive | 2016-09-05 11:30:00 |
+----+------------------+---------------------+
查询最终应返回以下内容,保留
根据mySQL的COUNT函数生成的列eventcounts,最常发生的前3个事件按其eventname分组
只有eventcount=1的2行,但仅当1在前3个eventcounts内时,因为有很多事件刚刚发生
曾经,因此会使我的前端过载
基于上表的预期结果示例:
+------------+------------------+
| eventcount | eventname |
+------------+------------------+
| 3 | machine1.started |
| 2 | machine1.stopped |
| 2 | cluster.alive |
| 1 | machine0.started |
| 1 | machine2.started |
+------------+------------------+
请注意,我不需要仅返回3行,而是需要具有3个最高事件计数的行
我用下面的查询字符串做了很多实验,包括多次选择和可疑案例。。。当条件允许时,但无法使其按我需要的方式工作
SELECT COUNT(id) AS 'eventcount', eventname
FROM eventlog
GROUP BY eventname
ORDER BY eventcount DESC;
什么是以高效的方式获得所需结果的最佳方法?MySQL中的这些类型的条件是痛苦的。一种方法使用变量。这里有一种方法不需要:
SELECT el.eventcount, el.eventname
FROM (SELECT COUNT(el.id) AS eventcount, el.eventname
FROM eventlog el
GROUP BY el.eventname
) el JOIN
(SELECT cnt
FROM (SELECT DISTINCT COUNT(el.id) as cnt
FROM eventlog el
GROUP BY el.eventname
) el
ORDER BY cnt DESC
LIMIT 3
) ell
ON ell.cnt = el.eventcount
ORDER BY el.eventcount DESC;
编辑:
使用变量的解决方案如下所示,包括计数为1时2的限制:
SELECT *
FROM (SELECT e.*,
(@rn1 := if(@c1 = eventcount, @rn1 + 1,
if(@c1 := eventcount, 1, 1)
)
) as rn
FROM (SELECT e.*,
(@rn := if(@c = eventcount, @rn,
if(@c := eventcount, @rn + 1, @rn + 1)
)
) as rank
FROM (SELECT COUNT(el.id) AS eventcount, el.eventname
FROM eventlog el
GROUP BY el.eventname
) e CROSS JOIN
(SELECT @c := 0, @rn := 0) params
ORDER BY eventcount DESC
) e CROSS JOIN
(SELECT @c1 := 0, @rn1 := 0) params
ORDER BY eventcount DESC
) e
WHERE rank <= 3 AND
(eventcount > 1 OR rn <= 2);
最里面的计数枚举计数。第二个在计数内枚举。实际上,这两个查询可以组合成一个子查询,但要小心。您可以尝试以下方法:
SELECT count(eventname), eventname FROM table
group by eventname
HAVING(count(eventname)) > 1
order by count(eventname) DESC
limit 3
这里有一种使用变量的方法 SQL Fiddle for it:
这应该可以重构一点,但它现在返回了正确的答案:
SELECT eventcount, eventname
FROM
(SELECT el.eventcount, el.eventname
FROM (SELECT COUNT(el.id) AS eventcount, el.eventname
FROM eventlog el
GROUP BY el.eventname
) el JOIN
(SELECT counts
FROM (SELECT DISTINCT COUNT(el.id) as counts
FROM eventlog el
GROUP BY el.eventname
) el
ORDER BY counts DESC
LIMIT 3
) el2
ON el2.counts = el.eventcount
WHERE el.eventcount != 1
UNION ALL
(SELECT el.eventcount, el.eventname
FROM (SELECT COUNT(el.id) AS eventcount, el.eventname
FROM eventlog el
GROUP BY el.eventname
) el JOIN
(SELECT counts
FROM (SELECT DISTINCT COUNT(el.id) as counts
FROM eventlog el
GROUP BY el.eventname
) el
ORDER BY counts DESC
LIMIT 3
) el2
ON el2.counts = el.eventcount AND el2.counts = 1
LIMIT 2)) tmp
ORDER BY tmp.eventcount DESC;
SQL FIDLE:如果可以使用临时表 预先计算事件计数并将结果存储在临时表中:
create temporary table tmp_eventcounts
select eventname, count(1) as eventcount
from eventlog
group by eventname
order by eventcount desc
;
create temporary table tmp_top3counts
select distinct eventcount
from tmp_eventcounts
order by eventcount desc
limit 3
;
tmp_事件计数的内容:
选择前3个事件计数并将其存储在另一个临时表中:
create temporary table tmp_eventcounts
select eventname, count(1) as eventcount
from eventlog
group by eventname
order by eventcount desc
;
create temporary table tmp_top3counts
select distinct eventcount
from tmp_eventcounts
order by eventcount desc
limit 3
;
tmp_Top3计数的内容:
现在选择eventcount前3名但eventcount>1的所有EventName。
还可以选择最多两个具有前3个eventcounts但eventcount=1的EventName。
使用UNION组合两个结果:
select eventcount, eventname
from tmp_top3counts
join tmp_eventcounts using(eventcount)
where eventcount > 1
union all (
select eventcount, eventname
from tmp_top3counts
join tmp_eventcounts using(eventcount)
where eventcount = 1
limit 2
)
order by eventcount desc;
结果:
| eventcount | eventname |
|------------|------------------|
| 3 | machine1.started |
| 2 | machine1.stopped |
| 2 | cluster.alive |
| 1 | machine2.reboot |
| 1 | machine3.started |
如果不能使用临时表,则可以使用临时表的定义替换临时表的引用,并创建一个高度不可读但有效的查询:
select eventcount, eventname
from (
select distinct eventcount
from (
select eventname, count(1) as eventcount
from eventlog
group by eventname
) tmp_eventcounts
order by eventcount desc
limit 3
) tmp_top3counts
join (
select eventname, count(1) as eventcount
from eventlog
group by eventname
) tmp_eventcounts using(eventcount)
where eventcount > 1
union all (
select eventcount, eventname
from (
select distinct eventcount
from (
select eventname, count(1) as eventcount
from eventlog
group by eventname
) tmp_eventcounts
order by eventcount desc
limit 3
) tmp_top3counts
join (
select eventname, count(1) as eventcount
from eventlog
group by eventname
) tmp_eventcounts using(eventcount)
where eventcount = 1
limit 2
)
order by eventcount desc;
)-
虽然这看起来很疯狂,但可以在PHP中轻松创建:
$tmp_eventcounts = "
select eventname, count(1) as eventcount
from eventlog
group by eventname
";
$tmp_top3counts = "
select distinct eventcount
from ( {$tmp_eventcounts} ) tmp_eventcounts
order by eventcount desc
limit 3
";
$sql = "
select eventcount, eventname
from ( {$tmp_top3counts} ) tmp_top3counts
join ( {$tmp_eventcounts} ) tmp_eventcounts using(eventcount)
where eventcount > 1
union all (
select eventcount, eventname
from ( {$tmp_top3counts} ) tmp_top3counts
join ( {$tmp_eventcounts} ) tmp_eventcounts using(eventcount)
where eventcount = 1
limit 2
)
order by eventcount desc
";
注意:看起来MySQL需要一次又一次地执行相同的子查询。但是它应该能够缓存结果并重用它们。@riggsfully不,它不会。样本数据的预期结果为5rows@Lamak好的观点这将正确地进行排名,但是如果eventcount=1在前3个结果中,OP只想返回其中的2个记录,这将不会限制这一点,并将返回测试用例中的所有4个记录above@Matt是的,你说得对,排名很好,它似乎运行效率很高,但不考虑事件计数的限制= 1……不同的计数组?呃?对于任何想知道的人来说:@Gordon Linoff和Matt的解决方案对我来说都非常有效。我接受了这个答案,因为查询更快完成。
$tmp_eventcounts = "
select eventname, count(1) as eventcount
from eventlog
group by eventname
";
$tmp_top3counts = "
select distinct eventcount
from ( {$tmp_eventcounts} ) tmp_eventcounts
order by eventcount desc
limit 3
";
$sql = "
select eventcount, eventname
from ( {$tmp_top3counts} ) tmp_top3counts
join ( {$tmp_eventcounts} ) tmp_eventcounts using(eventcount)
where eventcount > 1
union all (
select eventcount, eventname
from ( {$tmp_top3counts} ) tmp_top3counts
join ( {$tmp_eventcounts} ) tmp_eventcounts using(eventcount)
where eventcount = 1
limit 2
)
order by eventcount desc
";