1. 需求说明

由于业务更新,需要在原有的SQL分页查询基础上,添加一个条件,将一个字段带含有(“A”,“B”)字符串的的数据排除在外,排除字符串是根据不同的业务配置的,它是一个动态的参数。

若字段内容为:
- ABCD
- A
- BAA
- AAABBAA
排除内容为:BB,BC,D
则筛选后的结果为:A,BAA

测试数据(要求:过滤带有指定关键字的列):

INSERT INTO `content_xx` (`id`, `content`) VALUES (1, '沿西巴霞曲河谷,穿越“山南之南”');
INSERT INTO `content_xx` (`id`, `content`) VALUES (2, '甘肃西北的干旱戈壁是珍稀植物隐居的乐土');
INSERT INTO `content_xx` (`id`, `content`) VALUES (3, '安集海大峡谷之冬');
INSERT INTO `content_xx` (`id`, `content`) VALUES (4, '喀斯特瀑布 繁星般点缀了 219国道滇桂段');
INSERT INTO `content_xx` (`id`, `content`) VALUES (5, '海蚀拱 中国海岸的珍稀景观');
INSERT INTO `content_xx` (`id`, `content`) VALUES (6, '柴达木水上雅丹 “西部千岛湖”的变化、秘密与隐忧');
INSERT INTO `content_xx` (`id`, `content`) VALUES (7, '伟大的征途——布伦托海大迁徙');



2. 尝试

尝试过的方法:

  1. 对于这种排除多个字符串的查询,无法用到常规的函数,例如LIKE、UNION、FIND_IN_SET、NOT IN等。

    NOT LIKE只能判断单个字符串,NOT IN、FIND_IN_SET又只能精准匹配,无法从语句中提取关键字。


  1. 通过子查询一遍遍过滤。

    然后想到的是既然NOT LIKE可以排除一个,那我就一个个排除不就好了?通过NOT LIKE + EXISTS子查询语句的方式来排除每一个排除项。这种方法比较傻瓜式,且效率肉眼可见的低下,不适合作为首选方法。


  1. 考虑过在代码中通过正则查询,但是这种方法得自己做物理分页,而且得大幅度修改源代码,效率更低。



3. REGEXP 正则过滤

注意!!!


低版本的MySQL一些正则表达式都不起作用,会报错:1139 - Got error ‘repetition-operator operand invalid’ from regexp


可以参考这篇文章:1139 - Got error ‘repetition-operator operand invalid’ from regexp

我本地的MySQL(8.0)可以执行下面所有的正则,然后放到开发环境(5.7)就只有第三条可以正常使用(这一条还是我不断试出来的)。

select version() from dual;
在这里插入图片描述
在这里插入图片描述

将正则表达式作为参数拼接进去,就可以形成动态的过滤参数。

搜索的时候大概找到几种可用的方法,参考如下:

  1. ^((?:河|海岸|峡谷).)*$
SELECT *
FROM content_xx
WHERE content NOT REGEXP "(?:河|海岸|峡谷)"

  1. ^((?!河|海岸|峡谷).)*$
SELECT *
FROM content_xx
WHERE content REGEXP "^((?!河|海岸|峡谷).)*$"

  1. ^(.*(河|海岸|峡谷).*)$
SELECT *
FROM content_xx
WHERE content NOT REGEXP "^(.*(河|海岸|峡谷).*)$"

结果:

2	甘肃西北的干旱戈壁是珍稀植物隐居的乐土
4	喀斯特瀑布 繁星般点缀了 219国道滇桂段
6	柴达木水上雅丹 “西部千岛湖”的变化、秘密与隐忧
7	伟大的征途——布伦托海大迁徙

在这里插入图片描述

更多推荐