❗️你有0条未读消息

mysql中in与find_in_set的使用

15/53,每周一篇博,坚持!

  1. 写在前面

    最近在工作中误用了mysql的in查询,导致了一个线上问题,花了我一个下午的时间排查加修复。mysql算是我的一个薄弱项了,主要是没有系统性的训练过。一些没用过的查询方式使用的时候借助搜索引擎,中文技术领域里一些技术分享还是比较坑的,语焉不详的算是一部分,误人子弟的也不乏其人。

    这篇博文就主要整理一下我所梳理的mysql中in的用法及和find_in_set用法的差异所在。也许网上已经有很多的文章介绍了,但不乏一些介绍不够清晰的,我这里的博文都是经过实践验证的,不敢保证一定做到简洁明了人人能懂,但绝不做误人子弟之事。

  2. in和find_in_set简介

    这两个命令从字面 意思上来看,貌似都是用来查询某个字段是否在某个值范围内的意思。但实际上两者的使用场景上是有区别的,我那个线上问题就是在应该使用find_in_set的时候误用了in。

    • in
      首先in做的是值与值间的精确匹配,它的用法如下:

      column in (value1,value2,value3...)

      “…”表示后面可以继续跟参数,也就是说in操作可以有任意的参数,每个参数间用逗号分隔。
      语句将依次查询字段的值是否与参数给出的值匹配。如果匹配则表示查询成功。
      这里值得注意的是: 很多网上的文章说的是in比较的是等不等,也就是说column要和后面values组成的逗号序列值相等。这是不对的,实际上是要拿column的值依次和values组成的逗号序列值做匹配,如果value1和column值相等则算匹配成功,否则都算失败。

    • find_in_set
      而find_in_set是从一个以逗号分隔的字符串列表中查找某个指定的字符串,它的用法如下:

      find_in_set(str,"value1,value2,value3...")

      可以看出find_in_set操作只可以接受两个参数,只是第二个参数可以是一个任意长度的以逗号分隔的字符串列表。
      如果在第二个参数这个字符串列表中找到第一个参数时则匹配成功。

      不知道说清楚没有,再举个例子说明一下。

      如数据库表存储的是图书信息,图书信息都分门别类按照书目所属的类别存储,一本图书只属于一个类别。此时我们希望查询出计算机和通信工程两个分类的书籍信息,就可以使用in来查询。
      因为这明显是要将书目类别信息与给定的参数值做匹配的需求。

      然而如果另一个数据库表存储的是某个学生近期借阅的书籍信息,每个学生一条数据,其中借阅书籍字段存储了他近期所借阅的所有书籍的书号。此时我们希望查询出该学生近期是否借阅过某本书,这时就可以使用find_in_set来查询。因为数据库里借阅书籍字段存储的是一串以逗号分隔的书号,这明显是要在一串字符串分隔的数据中查找指定的字符的需求。

      从这两个小例子中可以看出,我们可以简单地以数据库存储的字段是否是逗号分隔的字符串列表来划分是否要使用find_in_set。

  3. 示例

    以我实际遇到的问题为例,我要处理的表数据存储的字段为readedPartnerIds:以逗号形式存储了服务商的id。
    我的需求是:数据库里每一条记录代表了一条发给服务商的消息,如果某个服务商阅读过这条消息后,将该服务商的id追加到已读服务商id字段中,如果该服务商未读,则弹出消息。

    开始我错误地使用了in操作:

    select * from table where #partnerId# in (readedPartnerIds);

    这导致查询不到结果,该显示的消息弹框未显示出来。(有一条例外,即恰好partnerId值为readedPartnerIds字段的第一个值)
    正确的写法应该使用 find_in_set操作:

    select * from table where find_in_set(#partnerId#,readedPartnerIds)

    这样就能正确的从数据库存储的服务商id列表中查出是否包含了该服务商id。

赞 赏

如果你觉得本文还不错的话也可以赞赏一点~