GROUP_CONCAT有限制

问题描述 投票:39回答:7

我有player-s与skill-s的多对多关系表

目标是通过单个查询列出球员及其“前3名技能”。

fiddle

create table player(
  id int primary key
);

create table skill(
  id int primary key,
  title varchar(100)
);

create table player_skills (
  id int primary key,
  player_id int,
  skill_id int,
  value int
);

查询:

SELECT 
p.id,  
group_concat(s.title  SEPARATOR ', ') as skills

FROM player p
LEFT JOIN player_skills ps ON ps.player_id = p.id
LEFT JOIN skill s ON s.id = ps.skill_id

WHERE ps.value > 2
-- skills limit 3 some how ...
group by p.id 
order by s.id


-- expected result
-- player_ID, skills
-- 1 , 'one'
-- 2 , 'one'
-- 3 , 'two, three, four'

正如您在小提琴中看到的那样,查询的结果仅缺少3种技能的限制。 我尝试了几种子查询的变化..连接等但没有效果。

mysql group-concat
7个回答
76
投票

一个有点hacky的方法是对GROUP_CONCAT的结果进行后处理:

substring_index(group_concat(s.title SEPARATOR ','), ',', 3) as skills

当然,这假设您的技能名称不包含逗号,并且其数量相当小。

fiddle

遗憾的是,feature requestGROUP_CONCAT支持明确的LIMIT条款仍然没有得到解决。

更新:正如用户Strawberry指出的那样,表player_skills应该将元组(player_id, skill_id)作为其主键,否则模式允许将相同的技能多次分配给玩家,在这种情况下group_concat将无法按预期工作。


18
投票

使用GROUP_CONCAT GLOBAL group_concat_max_len增加GROUP_CONCAT()函数长度最大长度为1024个字符。 你可以做的是在mysql中设置GLOBAL group_concat_max_len

SET GLOBAL group_concat_max_len = 1000000;

试试这个,它肯定会起作用。


7
投票

有一个更清洁的解决方案。把它包裹在另一个SELECT声明中。

SELECT GROUP_CONCAT(id) FROM (
    SELECT DISTINCT id FROM people LIMIT 4
) AS ids;

/* Result 134756,134754,134751,134750 */

5
投票

这是另一种解决方案。它包括一个解决关系的任意机制,并采用与你的略有不同的架构......

SELECT a.player_id
     , GROUP_CONCAT(s.title ORDER BY rank) skills
  FROM
     ( SELECT x.*, COUNT(*) rank
         FROM player_skills x
         JOIN player_skills y 
           ON y.player_id = x.player_id
          AND (y.value > x.value
           OR (y.value = x.value AND y.skill_id <= x.skill_id))
        GROUP 
           BY player_id, value, skill_id
       HAVING COUNT(*) <= 3
     ) a
  JOIN skill s
    ON s.skill_id = a.skill_id
 GROUP 
    BY player_id;

http://sqlfiddle.com/#!2/34497/18

顺便提一下,如果你有一个表示层/应用程序级代码,那么考虑在那里做所有GROUP_CONCAT的东西。它更灵活。


2
投票

你有可能使用MariaDB 10.3.3+

支持GROUP_CONCAT()中的LIMIT子句(MDEV-11297

SELECT p.id,  
   GROUP_CONCAT(s.title ORDER BY title  SEPARATOR ', ' LIMIT 3) as skills
FROM player p
LEFT JOIN player_skills ps ON ps.player_id = p.id
LEFT JOIN skill s ON s.id = ps.skill_id
WHERE ps.value > 2
GROUP BY p.id 
ORDER BY s.id;

db<>fiddle demo


0
投票

您可以使用用户变量模拟分区的row_number,然后限制行并应用group_concat

select p.id,
    group_concat(s.title separator ', ') as skills
from player p
left join (
    select distinct ps.player_id,
        ps.skill_id,
        @rn := if(@player_id = player_id, @rn+1, if(@player_id := player_id, 1, 1)) as seqnum
    from player_skills ps
    cross join (select @rn := 0, @player_id := null) x
    where ps.value > 2
    order by player_id, value desc
    ) ps on p.id = ps.player_id and ps.seqnum <= 3
left join skill s on ps.skill_id = s.id
group by p.id;

Demo

此方法不需要任何表读取多次。


0
投票

首先,设置组连接的限制,然后编写查询。

SET SESSION group_concat_max_len = 1200000;

select group_concat(column_name) from table_name group by column_name;

这里,1200000表示查询允许组串联数据最大为1200000个字符。

© www.soinside.com 2019 - 2024. All rights reserved.