MYSQL:按正则表达式模式分组

时间:2016-07-23 00:20:27

标签: php mysql regex pdo

我正在尝试进行统计跟踪。在我的数据库中,我存储引用的URL。我经常有类似以下内容的网址:

http://www2.trafficadbar.com/__a4w4
http://trafficadbar.com/__a4w4
http://www.trafficadbar.com/__a4w4
http://4acesmailer.com/credit_click.php?userid=2472&openkey=gbyp2vcm
http://4acesmailer.com/credit_click.php?userid=2714&openkey=gbyp2vcm
http://4acesmailer.com/credit_click.php?userid=2723&openkey=gbyp2vcm
http://4acesmailer.com/credit_click.php?userid=3245&openkey=gbyp2vcm
http://4acesmailer.com/credit_click.php?userid=3259&openkey=gbyp2vcm

我想知道如何在正则表达式模式上执行GROUP BY和COUNT。基本上我想要的是返回如下:

trafficadbar 3
4acesmailer 5 

目前,当我尝试进行GROUP BY时,它只适用于网址完全相同的情况。所以www.blah.com和blah.com是两个不同的结果,并且每个url变量更进一步?blah = 1& blahblah = 2作为另一个独特的群体,

我已经搜索了无数的解决方案,但它们似乎对所提出的问题非常具体,而且几乎所有解决方案似乎都显示了一些"非正则表达式"解决方法 - 这很好......如果我能找到一个可以应用的方法。

4 个答案:

答案 0 :(得分:1)

要从主机名检索顶级域之前的部分,您可以继续使用:

SELECT
  REVERSE(SUBSTRING(SUBSTRING_INDEX(rev_hostname, '.', 2),
          LOCATE('.', rev_hostname) + 1)
         ) domain
  , COUNT(id) hits
FROM (
  SELECT
    id
    , CONCAT(REVERSE(SUBSTRING_INDEX(SUBSTRING(referring_site, 8),
                                     '/', 1)), '.') rev_hostname
  FROM TestData
  ) T
GROUP BY domain
;

有:

  • 依赖所有 refer_site 来启动 http://
  • 将失败 - 例如, 4acesmailer.co.uk

如果需要,可以解决(在某种程度上)任何一个问题。

在行动SQL Fiddle中查看它(您的数据有所调整/扩展以涵盖更多案例)。

请评论是否需要调整/进一步详细说明。

答案 1 :(得分:0)

如果您只关心这两个值,那么这样的事情就可以了:

select case when yourcolumn like '%trafficadbar%' then 'trafficadbar' 
            when yourcolumn like '%4acesmailer%' then '4acesmailer' 
       end,
    count(*)
from yourtable 
group by 1

编辑,鉴于您的评论,这可能会更加动态,相对容易扩展:

select 
  replace(replace(replace(
     left(yourcolumn, locate('.com', yourcolumn) - 1), 
     'http://', ''), 
     'www.', ''), 
     'www2.', ''),
  count(*)
from yourtable 
group by 1

答案 2 :(得分:0)

我没有足够的技巧在SQL中可靠地完成这项工作;有太多可移动的部分:许多子域,可能有很多TLD(不仅仅是.com),可能存在格式错误的域等...

我的方法:选择所有内容并在PHP中解析。

在下面的示例中,我假设网址位于urls列中,并且您有一个date_added列,其中包含每个网址添加到数据库时的日期时间。相应地调整您的查询。

选择过去30天内添加的所有网址:

SELECT `urls` FROM `myTable`
WHERE `date_added` >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)

将所有结果放在$rows数组中,然后处理该数组以生成所需的报告

$rows = [...];//Associative array of all rows returned by the query above
$results = []; //will hold aggregate counts

foreach($rows as $row){   
    $host = parse_url($row['urls'],PHP_URL_HOST); //eg: www2.trafficadbar.com
    $matches = [];

    //find top level domain or skip to next row
    if(!preg_match('/[^\.]*\.[^\.]+$/',$host,$matches)) continue;        

    $domain = $matches[0]; //eg: trafficadbar.com

    //increment the count for this domain in results
    if(!isset($results[$domain])) $results[$domain]=0;
    $results[$domain]++;
}

根据您在OP中提供的输入,$results将为:

[
    'trafficadbar.com' => 3,
    '4acesmailer.com' => 5,
]

您会注意到,与您不同,我保留了顶级域名(例如:.com.net ...),因为ebay.comebay.ph完全不同域。我建议不要将它们混合成一个结果。

Live demo

答案 3 :(得分:0)

尽管@BeetleJuice的解决方案可行,并且可能比我选择的解决方案更可靠,但我选择了SQL解决方案

{{1}}

缺点是,它不是以http://w加注星标,而是加注http://random.sub.domain