在MYSQL中,如何在逗号分隔的列中搜索多个值并将结果分解为行,而不使用临时表?

oaxa6hgo  于 2023-04-19  发布在  Mysql
关注(0)|答案(2)|浏览(122)

数据:user_choices
| 身份证|用户标识|选择|
| --------------|--------------|--------------|
| 1|三|一二三|
| 二|五十五|五|
| 三|七八三|二六七|
| 四|四十五|一、四|
| 五|五|一二三四五六七|
我如何查询这个表来分解choices列,该列只显示值1或2或3或4或7,并按userid分组,如下所示?
| 用户标识|选择|
| --------------|--------------|
| 三|1|
| 三|二|
| 三|三|
| 七八三|二|
| 七八三|七|
| 四十五|1|
| 四十五|四|
| 五|1|
| 五|二|
| 五|三|
| 五|四|
| 五|七|
我尝试了以下方法,但结果包括56,应该省略。

select replace(substring(substring_index(uc.choices, ',', 1), CHAR_LENGTH(SUBSTRING_INDEX(uc.choices, ',', -1)), + 1), ',', '') choice,,
                uc.userid
from user_choices uc
         join (select 1 digit union all select 2 union all select 3 union all select 4 union all select 7) n on length(replace(uc.choices, ',', '')) < length(uc.choices) - n.digit
where choices regexp '[12347]'
order by uc.userid

注意:我知道这里的正则表达式并不完美(例如,匹配22)。这里的表永远不会接收到这个,所以我认为不需要更严格的正则表达式。
输出:
| 选择|用户标识|
| --------------|--------------|
| 1|三|
| 1|五|
| 1|五|
| 1|五|
| 1|五|
| 二|七八三|
这个尝试是基于this answer到另一个问题,但我不能完全让它为我的场景工作。
非常感谢您的帮助!

9avjhtql

9avjhtql1#

数字表技术的另一种选择是使用JSON。
诀窍在于,给定CSV字符串的格式(用逗号分隔的数字),我们可以很容易地将它们转换为有效的JSON值,只需用方括号将它们括起来;例如[1,2,3]是一个有效的JSON数组。然后,我们可以使用方便的JSON函数json_table()将数组解嵌套到行中。最后一步是过滤。
所以:

select t.userid, j.choice
from mytable t
cross join json_table( concat('[', t.choices, ']'), '$[*]' columns (choice int path '$') ) j
where j.choice in (1, 2, 3, 4, 7)
order by t.userid, j.choice
用户标识选择
1
1
四十五1
四十五
七八三
七八三

fiddle

8wigbo56

8wigbo562#

我不清楚你的sql到底是怎么失败的,但你似乎没有完全正确地使用这种方法。
首先,您应该只连接与每行中的选择数相匹配的数字(因此,1、2和3表示'1,6,7');要做到这一点,你需要计算逗号的数量,加一(因为比逗号多了一个选择),并与数字进行比较:

on char_length(choices)-char_length(replace(choices,',',''))+1 >= digit

你似乎在尝试类似的东西,但不太正确。
其次,要提取第n个选择,您需要使用substring_index来获取前n个选择,并再次使用它来获取最后一个:

substring_index(substring_index(choices,',',digit),',',-1)

我没有理解你的replace/substring到底想做什么,但是double substring_index要简单得多。
所以:

select
    substring_index(substring_index(uc.choices,',',digit),',',-1) choice,
    uc.userid
from user_choices uc
join (select 1 digit union all select 2 union all select 3 union all select 4 union all select 7) n
    on char_length(uc.choices)-char_length(replace(uc.choices,',',''))+1 >= digit
where uc.choices regexp '[12347]'
having choice in (1,2,3,4,7)
order by uc.userid

如果你有一些选择,而regexp不够好,你可以使用例如:

where find_in_set(1,uc.choices) or find_in_set(2,uc.choices) or find_in_set(3,uc.choices) or find_in_set(4,uc.choices) or find_in_set(7,uc.choices)

相关问题