V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
gossip
V2EX  ›  Python

pymysql 关于带参的正则查询问题

  •  
  •   gossip · 2021-12-15 11:24:07 +08:00 · 2135 次点击
    这是一个创建于 1074 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有个商品表,我打算通过品名查询,但考虑下这种商品名很乱,势必要用正则来取:
    +----+---------------------------------------+
    | id | name |
    +----+---------------------------------------+
    | 1 | r510vc 15.6 英寸笔记本 |
    | 2 | y400n 14.0 英寸笔记本电脑 |
    | 3 | g150th 15.6 英寸游戏本 |
    | 4 | x550cc 15.6 英寸笔记本 |
    | 5 | x240 超级本 |
    | 6 | u330p 13.3 英寸超级本 |
    | 7 | svp13226scb 触控超级本 |
    | 8 | ipad mini 7.9 英寸平板电脑 |
    | 9 | ipad air 9.7 英寸平板电脑 |
    | 10 | ipad mini 配备 retina 显示屏 |
    | 11 | ideacentre c340 20 英寸一体电脑 |
    | 12 | vostro 3800-r1206 台式电脑 |
    | 13 | imac me086ch/a 21.5 英寸一体电脑 |
    | 14 | at7-7414lp 台式电脑 linux ) |
    | 15 | z220sff f4f06pa 工作站 |
    | 16 | poweredge ii 服务器 |
    | 17 | mac pro 专业级台式电脑 |
    | 18 | hmz-t3w 头戴显示设备 |
    | 19 | 商务双肩背包 |
    | 20 | x3250 m4 机架式服务器 |
    | 21 | 商务双肩背包 |
    +----+---------------------------------------+

    比如输入电脑,就显示含有电脑关键字的。于是我写了个查询的类,下面定义一个依据名称查询的方法:

    def search_by_name(self):
    goods_name = input('请输入您要查询的商品名:')
    # sql_command = 'select * from goods where name regexp ".*%s.*"' % goods_name
    # self.execute_sql_command(sql_command)
    #self.cursor.execute('select * from goods where name regexp ".*%s.*"',[goods_name,])
    sql = 'select * from goods where name=%s'
    paras = (goods_name,)
    self.cursor.execute(sql,paras)
    for item in self.cursor.fetchall():
    print(item)

    1.被注释掉的 self.cursor.execute('select * from goods where name regexp ".*%s.*"',[goods_name,])一句是我想达到的目标,但是发现不成功

    于是我猜想可能是正则语句太复杂了?上面有一重引号,导致解析时候发生了错误
    2.为了验证呢,于是写了
    sql = 'select * from goods where name=%s'
    paras = (goods_name,)
    self.cursor.execute(sql,paras)

    这三行没问题,没有用正则,只是普通参数化查询,是可以成功的。
    3.另外非参数化的构造 sql 语句再执行的方法,也能把这个正则查询跑出来,但是会有 sql 注入问题(也就是上面被注释掉的前两行的方法)

    因为是 python 初学者,这个问题应该在前端做规则限制吧。但是还是想知道应该怎么写这种带参的正则查询呢?
    7 条回复    2021-12-16 14:53:13 +08:00
    ErenJaeger
        1
    ErenJaeger  
       2021-12-15 13:59:15 +08:00
    MySQL 正则还真没用过,可以用模糊查询 like
    peonone
        2
    peonone  
       2021-12-15 15:41:25 +08:00   ❤️ 1
    试试
    self.cursor.execute('select * from goods where name regexp %s',[f".*{goods_name}.*",])
    gossip
        3
    gossip  
    OP
       2021-12-15 15:55:26 +08:00
    @peonone 正解了,想问下大佬,这个问题出在哪了呀,为啥里面有双引号就不行呢?
    另外您的写法从哪里看到的,我谷歌了一上午没找到好的方法
    dayeye2006199
        4
    dayeye2006199  
       2021-12-16 03:44:20 +08:00
    您这自己拼 SQL ,眼看着要被注入攻击的感觉;用 prepared statement 把
    peonone
        5
    peonone  
       2021-12-16 11:26:47 +08:00   ❤️ 1
    @gossip 在 SQL 字符串里%s 需要是一个完整的参数值代位符,".*%s.*"这样是不行的。
    我也没找到相关的文档,从我的经验来的:)


    @dayeye2006199 只有被注释的前两行是拼 SQL 的方式,LZ 想解决的问题就是在使用 prepared statement 了。
    但还是要注意会把用户输入的内容当作正则来处理,比如用户输入".*",会匹配任意字符
    gossip
        6
    gossip  
    OP
       2021-12-16 12:09:22 +08:00
    @peonone 感谢啦,您说得没错,觉得这个问题这么解决还不是办法。不过也是没接触过前端,写了个增删改查 sql 的小程序练练手,只有后端的 python 代码。本来想用查询先都把结果干出来,然后 python 对结果进行正则的,后来想了下,觉得这样效率不高,还是放在数据库端了在查询的时候做了匹配。

    不知道真的生产环境下该怎么处理这种问题呢?
    peonone
        7
    peonone  
       2021-12-16 14:53:13 +08:00
    真实环境下这种场景不会使用正则去查询数据库的,效率太低,需要扫描整个表,对每行的商品名做正则匹配,IO 和 CPU 消耗都很高,一种解决办法是使用检索引擎,比如 ElasticSearch ,MySQL 也有全文检索功能 https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html ,可以用来实现个简单原型试试。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2645 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 05:32 · PVG 13:32 · LAX 21:32 · JFK 00:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.