d.r*_*aev 42 mysql group-concat
我有表player-s在许多一对多的关系与skill-s
目标是通过单个查询列出球员及其"前3名技能".
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
);
Run Code Online (Sandbox Code Playgroud)
查询:
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'
Run Code Online (Sandbox Code Playgroud)
正如您在小提琴中看到的那样,查询的结果仅缺少3种技能的限制.
我尝试了几种子查询的变化..连接等但没有效果.
Nik*_* B. 79
一种有点hacky的方法是对后果进行后处理GROUP_CONCAT:
substring_index(group_concat(s.title SEPARATOR ','), ',', 3) as skills
Run Code Online (Sandbox Code Playgroud)
当然,这假设您的技能名称不包含逗号,并且其数量相当小.
一个功能请求用于GROUP_CONCAT支持一个明确的LIMIT条款是可惜还是没有得到解决.
更新:正如用户草莓所指出的那样,该表player_skills应该将元组(player_id, skill_id)作为其主键,否则该模式允许将相同的技能多次分配给玩家,在这种情况下group_concat将无法按预期工作.
小智 19
GROUP_CONCAT使用GLOBAL group_concat_max_len
GROUP_CONCAT()最大长度增加函数长度为1024个字符.
你可以做的是设置GLOBAL group_concat_max_len在mysql中
SET GLOBAL group_concat_max_len = 1000000;
Run Code Online (Sandbox Code Playgroud)
试试这个,它肯定会起作用.
Luk*_*zda 11
如果您使用的是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;
Run Code Online (Sandbox Code Playgroud)
有一个更清洁的解决方案.把它包装在另一个SELECT声明中.
SELECT GROUP_CONCAT(id) FROM (
SELECT DISTINCT id FROM people LIMIT 4
) AS ids;
/* Result 134756,134754,134751,134750 */
Run Code Online (Sandbox Code Playgroud)
这是另一种解决方案.它包括一个解决关系的任意机制,并采用与你的略有不同的架构......
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;
Run Code Online (Sandbox Code Playgroud)
http://sqlfiddle.com/#!2/34497/18
顺便提一下,如果你有一个表示层/应用程序级代码,那么考虑在那里做所有GROUP_CONCAT的东西.它更灵活.
| 归档时间: |
|
| 查看次数: |
58519 次 |
| 最近记录: |