获得每月最常见/最常见的价值

时间:2016-08-30 08:51:39

标签: mysql sql database laravel eloquent

我有一个看起来像这样的表:

 id | age |       date
----|-----|--------------------
 1  | 18  | 2016-07-1 00:00:00
 2  | 20  | 2016-07-1 00:00:00
 3  | 20  | 2016-07-1 00:00:00
 4  | 22  | 2016-08-1 00:00:00
 5  | 22  | 2016-08-1 00:00:00
 6  | 30  | 2016-08-1 00:00:00
 7  | 25  | 2016-09-1 00:00:00

我需要获得每个月+年最常见的年龄。

到目前为止我有这个问题:

$ages = User::selectRaw('age, MONTH(date) as month, YEAR(date) as year, count(*) as count')
        ->groupBy(['age', 'month', 'year'])
        ->orderBy('year', 'asc')
        ->orderBy('month', 'asc')
        ->get();

这仅获得每个月+年的每个年龄的计数。我需要看起来像这样的东西:

[
  {
    "age": 20,
    "month": 7,
    "year": 2016,
  },
  {
    "age": 22,
    "month": 8,
    "year": 2016,
  },
  {
    "age": 25,
    "month": 9,
    "year": 2016,
  }
]

即。对于7月(月== 7)2016年,有两个20和一个18,所以20是最常见的年龄。对于2016年8月,最常见的是22,依此类推......

对此有什么好的查询?感谢。

4 个答案:

答案 0 :(得分:0)

select substr(max(concat(lpad(count,10,'0'),age)),11) as age, month, year
  from (
   select age, MONTH(date) as month, YEAR(date) as year, count(*) as count
     from test6
    group by age, MONTH(date), YEAR(date)
  ) A
 group by month, year
 order by year, month

substr(max(concat(lpad(count,10,'0'),age)),11)汇编字符串“count-age”,获取最大值(最大计数行数(*)),并缩短“年龄”。

答案 1 :(得分:0)

试试这个

$ages = User::selectRaw('age, MONTH(date) as month, YEAR(date) as year, count(*) as count')
    ->groupBy(['age', 'month', 'year'])
    ->orderBy('year', 'asc')
    ->orderBy('month', 'asc')
    ->havingRaw('count = MAX(count)')
    ->get();

答案 2 :(得分:0)

这个操作在MySQL中有点困难。这有三个选择:

  • 设计一个执行聚合两次的复杂查询
  • 使用变量
  • 利用“黑客”

第三个看起来像这样:

select yyyy, mm,
       substring_index(group_concat(age order by cnt desc), ',', 1) as mode
from (select age, year(date) as yyyy, month(date) as mm, 
             count(*) as cnt
      from test6 t
      group by age, MONTH(date), YEAR(date)
     ) t
group by yyyy, mm;

第一个看起来像这样:

select year(date), month(date), age
from test6 t
group by year(date), month(date)
having count(*) = (select count(*)
                   from test6 t2
                   where year(t2.date) = year(t.date) and
                         month(t2.date) = month(t.date)
                   group by age
                   order by count(*) desc
                   limit 1
                  );

请注意,这会返回与第一个查询稍有不同的结果。如果多个年龄段最常见,此版本将返回重复项。

答案 3 :(得分:0)

我不知道如何重新格式化,但在MySQL中,有效的查询可能如下所示:

SELECT a.* 
  FROM 
     ( SELECT DATE_FORMAT(date,'%Y-%m') yearmonth
            , age
            , COUNT(*) total 
         FROM my_table 
        GROUP 
           BY yearmonth
            , age
     ) a 
  JOIN 
     ( SELECT yearmonth
            , MAX(total) total 
         FROM 
            ( SELECT DATE_FORMAT(date,'%Y-%m') yearmonth
                   , age
                   , COUNT(*) total 
                FROM my_table 
               GROUP 
                  BY yearmonth
                   , age
            ) x 
        GROUP 
           BY yearmonth
     ) b 
    ON b.yearmonth = a.yearmonth 
   AND b.total = a.total;

如果两个年龄在给定月份的顶部并列,则此查询将返回两者。

如果允许“黑客”解决方案,这里有一个很好的......

SELECT yearmonth 
     , age 
  FROM 
     ( SELECT DATE_FORMAT(date,'%Y-%m') yearmonth
            , age 
         FROM my_table 
        GROUP 
           BY yearmonth
            , age 
        ORDER 
           BY yearmonth
            , COUNT(*) DESC
     ) x 
 GROUP 
    BY yearmonth;

对于绑定结果,此解决方案将以不确定的方式选择一个结果。根据文档,它也不能保证产生正确的结果。虽然在实践中它始终如此,但我更喜欢第一种解决方案。