MYSQL从用户

时间:2018-02-14 16:55:07

标签: mysql group-by limit group-concat

我提前道歉,因为我可能没有正确描述我的问题。我正在尝试编写一个查询,每个用户使用前5个最受欢迎的selected_user_items,并通过group_concat将每个用户的顶行连接到逗号分隔的字符串,然后按user_id分组。

例如,如果user_id为1,item_id为1,则为5行,item_id为2的两行,item_id为3的3行,4 5和6的单行,则结果为1,3 ,2,4,5。

这是我的示例表结构。

姓名:chosen_user_items

id | user_id | item_id
------------------------
1  | 1       | 1
2  | 1       | 4
3  | 1       | 19
4  | 1       | 10
5  | 1       | 13
.  | 1       | 1
.  | 1       | 11
.  | 1       | 18
.  | 1       | 212
.  | 1       | 654
.  | 2       | 1
.  | 2       | 28
.  | 2       | 568
.  | 2       | 112
.  | 2       | 354
.  | 3       | 4
.  | 3       | 4
.  | 3       | 19
.  | 3       | 212
.  | 3       | 654
.  | 3       | 4
.  | 3       | 4
.  | 3       | 253
.  | 3       | 187
.  | 3       | 212

这是我想要的输出的一个例子:

user_id | group_concat_results
------------------------------
1       | 1, 4, 19, 13, 212
2       | 1, 28, 568, 212, 354
3       | 4, 212, 19, 654, 253

这是我到目前为止的查询

SELECT `chosen_user_items`.`item_id`, COUNT(`chosen_user_items`.`item_id`) AS 'item_count' 
FROM `chosen_user_items` 
WHERE `chosen_user_items`.`user_id` = 1
GROUP BY `chosen_user_items`.`item_id` 
ORDER BY `item_count` DESC 
LIMIT 5

虽然这对单个用户来说非常有用,但我希望能够为所有用户运行此查询一次(为了避免执行数百或数千个数据库查询),并且必须使用一种语言手动连接结果比如PHP。

提前致谢。

3 个答案:

答案 0 :(得分:2)

通过某种排名,可以通过1次查询来完成。

select user_id, group_concat(item_id) from 
(
select 
  user_id
  ,item_id
  ,@item_rank := if(@current_item = user_id, @item_rank+1,1) as item_rank 
  ,@current_item:=user_id
  from
      (      
      select 
        user_id
        ,item_id
        ,count(*) aantal
      from chosen_user_items
      group by user_id,item_id
      order by user_id,count(*) desc
      ) a )b
      where item_rank <6
      group by user_id

这是一个sqlfiddle来测试它。

我只对group_concat的顺序有问题,因此不会对其进行排序。

尝试以下查询以查看group_concat之前的结果,也许你可以更好地连接它。

select 
  user_id
  ,item_id
  ,@item_rank := if(@current_item = user_id, @item_rank+1,1) as item_rank 
  ,@current_item:=user_id
  from
      (      
      select 
        user_id
        ,item_id
        ,count(*) aantal
      from chosen_user_items
      group by user_id,item_id
      order by user_id,count(*) desc
      ) a 

此查询根据您问题中的数据正确排序concat:

select user_id, group_concat(item_id) from 
(
select 
  user_id
  ,item_id
  ,@item_rank := if(@current_item = user_id, @item_rank+1,1) as item_rank 
  ,@current_item:=user_id
  from
      (      
      select 
        user_id
        ,item_id
        ,count(*) aantal
      from chosen_user_items
      group by user_id,item_id
      order by user_id,count(*) desc
      ) a )b
      where item_rank <6
      group by user_id
      order by user_id,item_rank asc

答案 1 :(得分:1)

使用R.

的解决方案

dbplyr包允许您直接针对数据库运行此脚本,而无需将数据拉入内存。如果您不想使用R,则可以render dbplyr从您的R语句生成的SQL查询。

library(tidyverse)
library(stringr)

# --- Set Up ---
dat <- tribble(
  ~user_id, ~item_id,
  1, 1,
  1, 4,
  1, 19,
  1, 10,
  1, 13,
  1, 1,
  1, 11,
  1, 18,
  1, 212,
  1, 654,
  2, 1,
  2, 28,
  2, 568,
  2, 112,
  2, 354,
  3, 4,
  3, 4,
  3, 19,
  3, 212,
  3, 654,
  3, 4,
  3, 4,
  3, 253,
  3, 187,
  3, 212
)

# --- Prep --- 
pre <- dat %>% 
  group_by(user_id) %>% 
  arrange(user_id, item_id) %>% 
  add_count(item_id) %>% 
  rename(
    n_items = n
  ) %>% 
  distinct(user_id, item_id, .keep_all = TRUE) %>% 
  top_n(5, n_items) %>% 
  slice(1:5) %>% 
  arrange(user_id, desc(n_items)) 

# --- Solve ---
# Hacky
solution_one <- pre %>% 
  mutate(collapsed = str_c(item_id, collapse = ", ")) %>% 
  slice(1) %>% 
  select(user_id, collapsed)

# Ideal
solution_two <- pre %>%
  nest() %>% 
  mutate(
    collapsed = data %>% 
      map("item_id") %>% 
      map_chr(str_c, collapse = ", "))

输出:

solution_two
#> # A tibble: 3 x 3
#>   user_id             data            collapsed
#>     <dbl>           <list>                <chr>
#> 1       1 <tibble [5 x 2]>     1, 4, 10, 11, 13
#> 2       2 <tibble [5 x 2]> 1, 28, 112, 354, 568
#> 3       3 <tibble [5 x 2]> 4, 212, 19, 187, 253

这是最佳解决方案,因为您在嵌套列表列item_id中保留data及其计数。

答案 2 :(得分:-1)

要解决这个问题,我认为您需要采取4个不同的步骤。

首先,您需要选择/选择/订购将要显示的行。 这可以使用row_number和partition by来完成(这不能在MYSQL中使用,但在本指南中,它们向您展示了MYSQL等效解决方案https://blog.sqlauthority.com/2014/03/09/mysql-reset-row-number-for-each-group-partition-by-row-number/

其次,您需要过滤row_number低于5的行,这将表现为&#34;限制5&#34;每个查询。

第三步,您需要为每个用户提供5条记录,转换为5列。 这可以使用数据透视表完成。在这里,您可以找到您需要做的示例:MySQL pivot table

最后一步:您需要做的只是连接5列中的每一列,您将获得每个用户所需的信息。

我希望这能澄清

编辑:使用功能GROUP_CONCAT将允许您替换最后2个步骤