MySQL函数find_in_set介绍

本文介绍了在MySQL中如何准确地查询担任特定职务的人员。通过对比模糊查询与使用find_in_set函数的方法,阐述了find_in_set函数的优势,并给出了具体的SQL示例。

转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/78611636,建议读者阅读原文,确保获得完整的信息

场景介绍

人有时会身兼数职,需要查找出其中担任某一职务的都有哪些人,如下面position字段,不同的职务用数字表示,多个职务以逗号隔开。

这里写图片描述

先要查找出担任1职务的人员,通过以下两种方式来查询。

方式一

采用模糊查询,匹配出1职务的记录,如下SQL:

select * from user where position like '%1%'

查询结果如下,仔细观察你会发现position为10的也被查出来了,但这个不符合业务要求。

这里写图片描述

方式二

采用MySQL的原生函数find_in_set(str,array)来查询,SQL如下:

select * from user where find_in_set(1,position)

查询结果如下,符合要求。

这里写图片描述

函数介绍

FIND_IN_SET(str,strlist),注意其中strlist只识别英文逗号。

这里写图片描述

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_find-in-set

<think>我们正在讨论SQLServer中替代MySQLFIND_IN_SET函数的问题。FIND_IN_SET函数MySQL中用于查找一个字符串在一个逗号分隔的字符串列表中出现的位置。在SQLServer中没有直接对应的函数,但我们可以通过其他方式实现类似功能。常见的实现方法包括:1.使用字符串分割函数将逗号分隔的字符串拆分成表,然后使用查询判断值是否存在。2.使用LIKE运算符进行模式匹配(注意:这种方法有局限性,比如可能会误匹配部分字符串)。3.使用XML方法进行拆分。这里我们主要介绍第一种方法,因为它是比较通用且准确的方法。具体步骤:-在SQLServer2016及以上版本,可以使用STRING_SPLIT函数来拆分逗号分隔的字符串。-对于更早的版本,我们可以自己创建一个分割函数。以下是一个自定义分割函数的示例,它将逗号分隔的字符串拆分成一个表:```sqlCREATEFUNCTIONdbo.SplitString(@strNVARCHAR(MAX),@delimiterCHAR(1))RETURNS@resultsTABLE(ValueNVARCHAR(MAX))ASBEGINDECLARE@xXMLSET@x=CAST('<s>'+REPLACE(@str,@delimiter,'</s><s>')+'</s>'ASXML)INSERTINTO@resultsSELECTT.c.value('.','NVARCHAR(MAX)')ASValueFROM@x.nodes('/s')T(c)RETURNEND```然后,我们可以这样使用这个函数来模拟FIND_IN_SET:```sqlDECLARE@searchStrNVARCHAR(100)='apple'DECLARE@listNVARCHAR(MAX)='banana,apple,orange'--方法1:检查是否存在SELECTCASEWHENEXISTS(SELECT1FROMdbo.SplitString(@list,',')WHEREValue=@searchStr)THEN1ELSE0ENDASFound--方法2:返回位置(这里我们返回匹配的行号,由于集合是无序的,所以这个行号并不完全等同于FIND_IN_SET的位置,但我们可以通过排序来模拟)SELECTROW_NUMBER()OVER(ORDERBY(SELECTNULL))ASPosition,ValueFROMdbo.SplitString(@list,',')```注意:在MySQL中,FIND_IN_SET返回的是从1开始的位置,但是我们的方法返回的行号可能会因为拆分方式的不同而不一定与原始顺序一致。如果我们希望保持原始顺序,可以在拆分时保留顺序。我们可以修改上面的函数,使其返回位置信息。下面是增强版本的分割函数,它返回每个值及其位置:```sqlCREATEFUNCTIONdbo.SplitStringWithPosition(@strNVARCHAR(MAX),@delimiterCHAR(1))RETURNS@resultsTABLE(PositionINTIDENTITY(1,1),ValueNVARCHAR(MAX))ASBEGINDECLARE@xXMLSET@x=CAST('<s>'+REPLACE(@str,@delimiter,'</s><s>')+'</s>'ASXML)INSERTINTO@results(Value)SELECTT.c.value('.','NVARCHAR(MAX)')ASValueFROM@x.nodes('/s')T(c)RETURNEND```这样,我们就可以通过位置来模拟FIND_IN_SET:```sqlDECLARE@searchStrNVARCHAR(100)='apple'DECLARE@listNVARCHAR(MAX)='banana,apple,orange'SELECTPositionFROMdbo.SplitStringWithPosition(@list,',')WHEREValue=@searchStr```如果在列表中没有找到,则不会返回任何行,类似于MySQL中返回0的情况。我们可以使用ISNULL((SELECTPosition...),0)来返回0。另外,在SQLServer2016及以上版本,我们可以使用STRING_SPLIT,但注意这个函数不保证返回顺序,也不返回位置。所以如果我们只需要判断是否存在,可以这样:```sqlDECLARE@searchStrNVARCHAR(100)='apple'DECLARE@listNVARCHAR(MAX)='banana,apple,orange'SELECT1WHEREEXISTS(SELECT1FROMSTRING_SPLIT(@list,',')WHEREvalue=@searchStr)```但是,如果我们想要位置,则仍然需要使用自定义函数。总结:在SQLServer中替代MySQLFIND_IN_SET函数,我们可以:1.使用自定义分割函数(适用于所有版本),并且可以返回位置。2.使用STRING_SPLIT函数(仅2016+),但只能判断存在性,不能保证顺序。因此,根据需求选择合适的方法。相关问题:1.在SQLServer中如何将分隔字符串拆分为多行?2.SQLServer中有没有内置的字符串分割函数?3.如何优化SQLServer中的字符串分割操作以提高性能?</think> 在 SQL Server 中,没有直接等同于 MySQL `FIND_IN_SET()` 的内置函数,但可以通过以下几种方法实现相同功能: ### 方法 1:使用 XML 方法(兼容所有版本) ```sql CREATE FUNCTION dbo.FindInSet(@search VARCHAR(100), @list VARCHAR(MAX)) RETURNS INT AS BEGIN RETURN ( SELECT Position = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM ( SELECT Split.a.value('.', 'VARCHAR(100)') AS Value FROM ( SELECT CAST('<x>' + REPLACE(@list, ',', '</x><x>') + '</x>' AS XML) AS Data ) AS a CROSS APPLY Data.nodes('/x') AS Split(a) ) AS t WHERE Value = @search ) END ``` ### 方法 2:使用 STRING_SPLIT(SQL Server 2016+) ```sql CREATE FUNCTION dbo.FindInSet(@search VARCHAR(100), @list VARCHAR(MAX)) RETURNS INT AS BEGIN RETURN ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM STRING_SPLIT(@list, ',') WHERE value = @search ) END ``` ### 方法 3:使用 JSON(SQL Server 2016+) ```sql CREATE FUNCTION dbo.FindInSet(@search VARCHAR(100), @list VARCHAR(MAX)) RETURNS INT AS BEGIN RETURN ( SELECT [key] + 1 FROM OPENJSON('["' + REPLACE(@list, ',', '","') + '"]') WHERE value = @search ) END ``` ### 使用方法示例 ```sql -- 返回 'banana' 的位置(结果为 2) SELECT dbo.FindInSet('banana', 'apple,banana,orange') -- 未找到时返回 0 SELECT dbo.FindInSet('grape', 'apple,banana,orange') ``` ### 性能说明 1. **XML/JSON 方法** - 适用所有版本 - 处理长字符串时注意性能 2. **STRING_SPLIT** - 只支持 2016+ - **重要**:不保证返回顺序(需额外排序逻辑) - 官方文档明确说明不保证顺序[^1] 3. **索引优化** - 频繁查询建议存储规范化数据 - 避免在 WHERE 子句中直接使用函数计算 ### 替代方案建议 对高频查询场景,建议: 1. 建立关联表替代逗号分隔值 2. 使用临时表存储分割后的值 3. 通过计算列预先存储位置信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值