我提前道歉,因为我可能没有正确描述我的问题。我正在尝试编写一个查询,每个用户使用前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。
提前致谢。
答案 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个步骤