2017-07-27 21 views
-1

我想查找最受欢迎的值并按月排列结果。 我的意思是,按月出现的价值最高。SQL如何找到最热门的按月排序

我做了大量的研究和一些答案,以找到最受欢迎的产品。通常情况下,该解决方案是一组由治安与限位1 像这样:Find most frequent value in SQL column


这里是我的示例表。 让我们试着找出每个人最喜欢的颜色。

表picked_colors

| Color | Name | Month | 
|--------|------|-------| 
| Yellow | Tom | 04 | 
| Red | Tom | 04 | 
| Yellow | Tom | 04 | 
| Blue | Tom | 03 | 
| Red | Sam | 04 | 
| Pink | Sam | 04 | 
| Pink | Sam | 04 | 
| Yellow | Sam | 03 | 

如此看来,4月份,汤姆首选黄色(他把它捡了两次VS一次红色的),并且他喜欢在三月的蓝色。 Sam最喜欢的一个是四月份的粉红色,三月份是黄色。

所以我想返回 一个表,其中名称=汤姆

月/彩色
04 /黄
03 /蓝

,并在那里名称=山姆

月份/颜色
04 /粉色
03 /黄


我想出头真的不喜欢的工作,例如这个,我可以找到汤姆多少次,每月每个喜欢的颜色。有了这个,我可以选择的最大值作为最喜欢的一个,但我不知道如何:

SELECT MONTH(month), color, COUNT(color) 
FROM picked_colors 
WHERE name = 'Tom' 
GROUP BY color, MONTH(month) 
ORDER BY MONTH(month) desc; 

返回:

月/颜色/计数
04 /黄色/ 2
04 /红/ 1
03/blue/1

其实它正是我所需要的,除了第二行我不想要。 我想到了max(count()),但它不被mysql允许。

有人吗? 非常感谢。

+0

向我们展示了 “很多东西”,你试过。我们需要知道您目前如何尝试解决这个问题,因为您很可能已经拥有大部分解决方案。 – user2366842

+0

如果最喜欢的项目有领带,你想要什么样的结果? –

+0

@ user2366842我试图让它更清楚。你可以吗? – Cyril

回答

0

此代码有效。

因为您可能会有重复,并且您只需要为每个用户/月份组合提供一个答案,所以我们必须通过解决方案获得更高级的解决方案。

该解决方案首先根据我们关心的每个组合(aggregated_picked_colors子查询)有多少行进行聚合,然后为每个我们关心的组合(sorted_picked_colors子查询)分配颜色数量的排名。顶级查询然后只是从ranking_picked_colors中提取排名最高的解决方案。

上增加这些排名列计数器的方法的更多细节,请访问:ROW_NUMBER() in MySQL

/* 
create table picked_colors (
    color varchar(10), 
    name varchar(10), 
    month tinyint 
); 

insert into picked_colors (color, name, month) values ('Yellow', 'Tom', 4); 
insert into picked_colors (color, name, month) values ('Red', 'Tom', 4); 
insert into picked_colors (color, name, month) values ('Yellow', 'Tom', 4); 
insert into picked_colors (color, name, month) values ('Blue', 'Tom', 3); 
insert into picked_colors (color, name, month) values ('Red', 'Sam', 4); 
insert into picked_colors (color, name, month) values ('Pink', 'Sam', 4); 
insert into picked_colors (color, name, month) values ('Pink', 'Sam', 4); 
insert into picked_colors (color, name, month) values ('Yellow', 'Sam', 3); 
*/ 

select 
    name, month, color 
from 
    (
    select 
     @row_num := IF(@prev_value=concat_ws('', name, month),@row_num+1,1) as row_number, 
     color, name, month, row_count, 
     @prev_value := concat_ws('', name, month) as prev_value 
    from 
     (
     select 
      name, month, color, count(*) as row_count 
     from 
      picked_colors 
     group by 
      name, month, color 
    ) aggregated_picked_colors, 
     (select @row_num := 1) x, 
     (select @prev_value := '') y 
    order by 
     name, month, row_count desc 
) ranked_picked_colors 
where 
    row_number = 1 
order by 
    name, month desc 

返回:

+------+-------+--------+ 
| name | month | color | 
+------+-------+--------+ 
| Sam |  4 | Pink | 
| Sam |  3 | Yellow | 
| Tom |  4 | Yellow | 
| Tom |  3 | Blue | 
+------+-------+--------+ 

编辑:添加说明/演练

的这里的主要目标是我们想要获取每组数据t我们正在汇总的帽子(在这种情况下,是每个名称/月份的组合),并根据它们的行数对颜色进行排序。然后,我们要插入一个新列到这些结果与明确的排名,将颜色拥有最行,其颜色有下一个最行等

当我们开始,我们不是真的准备好排列这些事情,我们有多行说“黄色”,但我们希望数据显示“黄色有5行”或沿着这些行。因此,我们写的第一个查询做这种聚合:

select 
    name, month, color, count(*) as row_count 
from 
    picked_colors 
group by 
    name, month, color; 

这将返回:

+------+-------+--------+-----------+ 
| name | month | color | row_count | 
+------+-------+--------+-----------+ 
| Sam |  3 | Yellow |   1 | 
| Sam |  4 | Pink |   2 | 
| Sam |  4 | Red |   1 | 
| Tom |  3 | Blue |   1 | 
| Tom |  4 | Red |   1 | 
| Tom |  4 | Yellow |   2 | 
+------+-------+--------+-----------+ 

这说明,每个名称和月,每个颜色多少行了。

接下来,我们要证明,对于每个名称和月,其颜色有最行,其颜色有第二个最行等,这逻辑是最令人费解。

的这里的想法是,在表定义,我们插入这些行:

(select @row_num := 1) x, 
(select @prev_value := '') y 

这些命令基本上初始化这些变量。只提供X和Y名称是因为我们必须给这些“子查询”一个名称,它们实际上并未在任何地方使用。

内的查询,我们使用这些变量。实际上,他们检查颜色/名称组合是否从前一行更改过。如果它们改变了,那么我们将@row_num设置为1,如果它们没有改变,那么我们就增加它。我们必须小心地按照与我们比较相邻行相同的标准对此查询进行排序;改变排序顺序会破坏逻辑。

select 
    @row_num := IF(@prev_value=concat_ws('', name, month),@row_num+1,1) as row_number, 
    color, name, month, row_count, 
    @prev_value := concat_ws('', name, month) as prev_value 
from 
    (
    select 
     name, month, color, count(*) as row_count 
    from 
     picked_colors 
    group by 
     name, month, color 
) aggregated_picked_colors, 
    (select @row_num := 1) x, 
    (select @prev_value := '') y 
order by 
    name, month, row_count desc; 

这将返回:

+------------+--------+------+-------+-----------+------------+ 
| row_number | color | name | month | row_count | prev_value | 
+------------+--------+------+-------+-----------+------------+ 
|   1 | Yellow | Sam |  3 |   1 | Sam3  | 
|   1 | Pink | Sam |  4 |   2 | Sam4  | 
|   2 | Red | Sam |  4 |   1 | Sam4  | 
|   1 | Blue | Tom |  3 |   1 | Tom3  | 
|   1 | Yellow | Tom |  4 |   2 | Tom4  | 
|   2 | Red | Tom |  4 |   1 | Tom4  | 
+------------+--------+------+-------+-----------+------------+ 

这里,我们可以忽略“prev_value”专栏中,我们实际上并不希望这些结果,我们只是设定要使用这个变量,当我们考察下一行。重要的是看看我们有相同的名称和月份,row_count最高的颜色row_number = 1,row_count次高的颜色row_number = 2等。

最后一步是查询只需要我们想要的字段,以及row_number = 1的行。这些行对应于每个名称/月份组合的最高频率颜色。

select 
    name, month, color 
from 
    (
    select 
     @row_num := IF(@prev_value=concat_ws('', name, month),@row_num+1,1) as row_number, 
     color, name, month, row_count, 
     @prev_value := concat_ws('', name, month) as prev_value 
    from 
     (
     select 
      name, month, color, count(*) as row_count 
     from 
      picked_colors 
     group by 
      name, month, color 
    ) aggregated_picked_colors, 
     (select @row_num := 1) x, 
     (select @prev_value := '') y 
    order by 
     name, month, row_count desc 
) ranked_picked_colors 
where 
    row_number = 1 
order by 
    name, month desc 

这将返回:

+------+-------+--------+ 
| name | month | color | 
+------+-------+--------+ 
| Sam |  4 | Pink | 
| Sam |  3 | Yellow | 
| Tom |  4 | Yellow | 
| Tom |  3 | Blue | 
+------+-------+--------+ 
+0

非常感谢。你能解释一下代码吗?这是相当先进的,我无法理解它的一切。 – Cyril

+0

我会在几个小时内写出详细的演练,也许是在一天结束的时候。对不起,我需要首先完成工作。 –

+0

我冲你详细的演练。现在非常清楚。非常感谢你的时间和解释。 – Cyril