MySQL:如何查询指定整数存在于CSV格式文本列的记录
问题描述
现有一张数据表,其中linked_folders为文本类型字段,以CSV格式存储其他记录的引用,示例数据如下:
+----+----------------+ | id | linked_folders | +----+----------------+ | 90 | NULL | | 91 | NULL | | 92 | 123,1,4,40 | | 93 | 123,1 | | 94 | NULL | | 95 | 235,8 | | 96 | 90 | | 97 | NULL | | 98 | NULL | | 99 | NULL | +----+----------------+
给定$id = 90,想要执行类似下面的伪查询:
SELECT * FROM my_table WHERE id = $id OR $id is in linked_folders
预期返回id为90和96的行。需求是匹配指定值存在于linked_folders字段的记录,但因为无法确定值前后是否有逗号,普通LIKE语句无法准确满足需求,求替代方案。
解决方案
方法1:拼接分隔符后精准匹配
给linked_folders字段前后都加上逗号,同时给目标id也包裹逗号,再用LIKE匹配,彻底避免部分值误判的问题:
SELECT * FROM my_table WHERE id = 90 OR CONCAT(',', linked_folders, ',') LIKE '%,90,%';
比如linked_folders值为90时,拼接后变成,90,,能精准匹配%,90,%;如果是190,20这类包含90但不是独立值的情况,拼接后是,190,20,,不会被匹配到。
方法2:利用数据库内置的CSV处理函数
不同数据库提供了专门处理逗号分隔字符串的函数,直接用这些函数更简洁:
- MySQL:用
FIND_IN_SET函数,专门查找值在逗号分隔字符串中的位置,找到则返回大于0的结果:
SELECT * FROM my_table WHERE id = 90 OR FIND_IN_SET(90, linked_folders) > 0;
注:FIND_IN_SET会自动忽略NULL值,无需额外处理。
- PostgreSQL:将字符串转成数组后用
ANY匹配:
SELECT * FROM my_table WHERE id = 90 OR 90 = ANY(string_to_array(linked_folders, ','));
- SQL Server:用
STRING_SPLIT拆分后关联匹配:
SELECT DISTINCT t.* FROM my_table t LEFT JOIN STRING_SPLIT(t.linked_folders, ',') s ON s.value = '90' WHERE t.id = 90 OR s.value IS NOT NULL;
方法3:重构数据表(最优长期方案)
如果数据量较大或需要频繁执行这类查询,建议直接重构表结构,用关联表替代CSV存储:
新建一张folder_links表,包含parent_id(原表的id)和linked_id(关联的记录id)两个字段,把原表中linked_folders的每个值拆成单独的行。比如原表id=96的linked_folders是90,就在关联表插入一行(96,90);id=92的linked_folders是123,1,4,40,就插入四行(92,123)、(92,1)、(92,4)、(92,40)。
之后查询用关联方式,效率更高也更符合数据库设计规范:
SELECT t.* FROM my_table t LEFT JOIN folder_links fl ON t.id = fl.parent_id WHERE t.id = 90 OR fl.linked_id = 90;
内容的提问来源于stack exchange,提问作者ESB691
相关产品推荐
相关产品推荐

