【问题标题】:SQL : max occurence(s) for each valueSQL:每个值​​的最大出现次数
【发布时间】:2016-09-13 10:36:55
【问题描述】:

我有一个非常简单的表 (LOG),其中包含属性 MAC_ADDR、IP_SRC、IP_DST、URL、PROTOCOL。当 PROTOCOL='DNS' 时,我希望包含 IP_SRC、URL、#OfOccurrences 的前 n 行通过减少表中每个 IP_SRC 的 #OfOccurrences 来排序。

为了更清楚,我希望能够为我的表中的每个 IP_SRC 列出前 n 个访问次数最多的页面。

我可以像这样获取每个 IP_SRC 的访问次数最多的 URL:

select ip_src,url,cnt
from (
    select ip_src,url,count(*) as cnt,protocol
    from log as b group by ip_src,url order by ip_src,cnt desc
) as c
where cnt>=(select MAX(cpt)
            from (select count(*) as cpt from log as b
            where c.ip_src==b.ip_src group by ip_src,url)
           )
      and protocol='DNS';

但是,这个方案显然没有优化。

这是一个更实用的代码(每个 IP_SRC 的访问量最大的 URL):

select ip_src,url,cnt
from (select ip_src,url,count(*) as cnt
      from log where protocol='DNS'
      group by ip_src,url
      order by ip_src,cnt asc)
group by ip_src;

第二个选项更快!但是,我想要每个 IP_SRC 的 n 个访问次数最多的页面,但我不知道该怎么做。

感谢您的帮助。

【问题讨论】:

  • 标记您正在使用的 dbms。 (那里有一些无效的 SQL...)
  • @jarlh 谢谢,确实是 sqlite

标签: sql sqlite join limit-per-group


【解决方案1】:

使用common table expression

WITH Temp1 AS (
  SELECT ip_src, url, count(*) AS cnt
  FROM Log
  WHERE protocol = 'DNS'
  GROUP BY ip_src, url
)
SELECT ip_src, url, cnt
FROM Temp1 AS T1
WHERE url IN (
  SELECT url
  FROM Temp1 AS T2
  WHERE T2.ip_src = T1.ip_src
    AND T2.cnt >= T1.cnt
  ORDER BY cnt DESC
  LIMIT 3  -- or whatever you want it to be
)
ORDER BY ip_src ASC, cnt DESC;

【讨论】:

  • 其实这个效率不如临时表。我的表很小(少于 2000 个条目),而您的解决方案需要超过 31 秒(RasperryPi 2)。对比一下,临时表只需要2秒!
【解决方案2】:
select x.ip_src, x.url, x.cnt
from (select ip_src,url,count(*) as cnt
      from log where protocol='DNS'
      group by ip_src,url
      order by ip_src, count(*) desc) AS x
group by x.ip_src;

你可以试试这个吗?

【讨论】:

  • 它并没有改进我的第二个代码,desc 应该是asc 以收集最高值。关键是每个 IP_SRC 有我想要的尽可能多的答案。在这里,我只有最高的价值……可能我不够清楚。
【解决方案3】:

最后,通过使用临时表,我可以设法得到我想要的。

--First create a temp table of occurences
CREATE TEMPORARY TABLE TEMP1 AS
SELECT ip_src,url,count(*) AS cnt
FROM LOG
WHERE protocol='DNS'
GROUP BY ip_src,url
ORDER BY ip_src,cnt,url DESC;
--Then use a classic limit per group query
SELECT T1.ip_src,T1.url,T1.cnt
FROM TEMP1 AS T1
WHERE T1.url in (
      SELECT T2.url
      FROM TEMP1 AS T2
      WHERE T2.ip_src=T1.ip_src and T2.cnt>=T1.cnt
      ORDER BY T2.cnt DESC
      LIMIT 3 --Or whatever you want it to be
)
ORDER BY T1.ip_src ASC,T1.cnt DESC;

如果有人知道如何在不需要临时表的情况下做同样的事情(或者解释一下为什么临时表是一个好的解决方案),请表达自己。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多