SQL如何按月查找最受欢迎的AND订单

时间:2017-07-27 15:19:26

标签: mysql

我想找到最受欢迎的价值并按月订购结果。 我的意思是,按月出现的价值最多。

我做了很多研究和一些答案,找到最受欢迎的产品。通常,解决方案是分组1和按顺序排列1。 像这样:Find most frequent value in SQL column

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

Table 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月份,汤姆喜欢黄色(他选择了两次而不是一次红色),他更喜欢蓝色的行军。 而山姆最喜欢的一个是4月粉红色,黄色是3月。

所以我想要一张返回的桌子 其中Name = Tom

月/颜色
04 /黄色 03 /蓝

并且Name = Sam

月/颜色
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 / red / 1
03 /蓝/ 1

实际上它正是我需要的,除了我不想要的第二行。 我想到了max(count())的东西,但mysql不允许这样做。

任何人? 非常感谢。

1 个答案:

答案 0 :(得分: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   |
+------+-------+--------+

编辑:添加说明/演练

这里的主要目标是我们想要收集我们聚合的每组数据(在这种情况下,每个名称/月的组合)并根据它们有多少行来排序颜色。然后,我们想要在这些结果中插入一个新列,并明确排列哪种颜色具有最多行,哪种颜色具有下一行,等等。

当我们开始时,我们还没准备好对这些事情进行排名,我们有多行说“黄色”,但我们希望数据显示“黄色有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   |
+------+-------+--------+