[英]GROUP_CONCAT with limit
我與player
-s 與skill
-s 有多對多關系
目標是通過一個查詢列出玩家及其“前三項技能”。
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 個技能的限制。
我嘗試了幾種子查詢的變體……加入等等,但沒有效果。
一種有點hacky的方法是對GROUP_CONCAT
的結果進行后處理:
substring_index(group_concat(s.title SEPARATOR ','), ',', 3) as skills
當然,這假設您的技能名稱不包含逗號並且它們的數量相當小。
很遺憾, GROUP_CONCAT
支持顯式LIMIT
子句的功能請求仍未解決。
更新:正如用戶Strawberry指出的那樣,表player_skills
應該將元組(player_id, skill_id)
作為其主鍵,否則模式允許將相同的技能多次分配給玩家,在這種情況下group_concat
將無法正常工作預期的。
使用GLOBAL group_concat_max_len
GROUP_CONCAT()
增加GROUP_CONCAT
函數長度,最大長度為 1024 個字符。
你可以做的是在mysql中設置GLOBAL group_concat_max_len
SET GLOBAL group_concat_max_len = 1000000;
試試這個,它肯定會起作用。
有一個更清潔的解決方案。 將它包裝在另一個SELECT
語句中。
SELECT GROUP_CONCAT(id) FROM (
SELECT DISTINCT id FROM people LIMIT 4
) AS ids;
/* Result 134756,134754,134751,134750 */
如果您使用的是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;
這是另一個解決方案。 它包括一種用於解決關系的任意機制,並采用與您的略有不同的模式......
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 的工作。 它更靈活。
您可以按照上述說明解決此類問題。
說明 1:設置組連接的限制,然后編寫您的查詢。
SET SESSION group_concat_max_len = 1200000;
說明2:然后您可以按照給定的兩個示例找出您的解決方案。
示例 1:
SELECT GROUP_CONCAT(app_id) AS ids FROM (
SELECT DISTINCT app_id FROM email_queue
) AS ids;
示例 2:
select GROUP_CONCAT(caption) from email_queue group BY process_type_id;
注1:這是example1和example2查詢的表結構
注 2:這里 1200000 表示查詢允許最多 1200000 個字符的組連接數據。
您可以使用用戶變量模擬分區的 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;
此方法不需要任何表多次讀取。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.