能否使用变量作为索引查询JSON_ARRAY而非硬编码固定值?
如何用变量作为JSON_ARRAY的动态索引
嘿,我明白你的困扰!在MySQL里直接把字段当作JSON数组的索引用->>"$[t1.arr_pos]"是行不通的,因为这个语法里的路径是字符串字面量,MySQL不会把t1.arr_pos解析成变量来动态替换。不过有两种可行的解决办法,看你的MySQL版本来选:
方法1:用CONCAT动态构建JSON路径(兼容MySQL 5.7+)
这个方法的核心是把变量arr_pos拼进JSON路径字符串里,再用JSON_EXTRACT提取值,最后用JSON_UNQUOTE去掉引号(和->>的效果一致)。另外注意调整随机数生成逻辑,避免索引越界:
SELECT t1.*, JSON_UNQUOTE(JSON_EXTRACT(t1.tickets, CONCAT('$[', t1.arr_pos, ']'))) AS random_ticket FROM ( SELECT c.id AS competition_id, JSON_ARRAYAGG(t.id) AS tickets, COUNT(t.id) AS tickets_sold, FLOOR(RAND() * COUNT(t.id)) AS arr_pos -- 数组索引从0开始,最大索引是COUNT(t.id)-1,这样生成的数不会越界 FROM competitions c JOIN tickets t ON t.competition_id = c.id WHERE c.end_date = '2021-01-15 15:00:00' AND c.tickets_sold > 0 GROUP BY c.id ) t1
关键点说明:
CONCAT('$[', t1.arr_pos, ']')会把arr_pos的数值动态拼进路径,比如arr_pos=2时,路径就变成$[2]JSON_EXTRACT根据拼接好的路径提取数组元素,JSON_UNQUOTE去掉JSON字符串的引号,得到原始的ticket ID- 原SQL里的
FLOOR(RAND()*(COUNT(t.id)-0+1))可能会生成等于COUNT(t.id)的数值,这会导致索引越界返回NULL,所以改成FLOOR(RAND() * COUNT(t.id))更安全
方法2:用JSON_TABLE拆分数组(MySQL 8.0+支持)
如果你的MySQL版本是8.0及以上,用JSON_TABLE把JSON数组拆成多行数据,再结合序号匹配会更直观:
WITH t1 AS ( SELECT c.id AS competition_id, JSON_ARRAYAGG(t.id) AS tickets, COUNT(t.id) AS tickets_sold, FLOOR(RAND() * COUNT(t.id)) AS arr_pos FROM competitions c JOIN tickets t ON t.competition_id = c.id WHERE c.end_date = '2021-01-15 15:00:00' AND c.tickets_sold > 0 GROUP BY c.id ) SELECT t1.*, j.ticket_id AS random_ticket FROM t1 JOIN JSON_TABLE( t1.tickets, '$[*]' COLUMNS ( ticket_id INT PATH '$', -- 提取数组中的每个ticket ID idx FOR ORDINALITY -- 生成从1开始的元素序号 ) ) j ON j.idx - 1 = t1.arr_pos; -- 序号减1后匹配0开始的arr_pos
关键点说明:
JSON_TABLE把JSON数组的每个元素拆成一行,FOR ORDINALITY会给每行分配一个从1开始的序号- 因为数组索引是从0开始的,所以用
j.idx - 1和arr_pos匹配,就能拿到对应的ticket ID
内容的提问来源于stack exchange,提问作者Dally
相关产品推荐
相关产品推荐

