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
j0shfan
V2EX  ›  Python

Python 中使用不定长字典构造 sql 语句问题

  •  
  •   j0shfan · 2020-03-27 16:40:30 +08:00 · 2390 次点击
    这是一个创建于 1462 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在有一个需要 在程序中使用不定长的字典构造 sql 语句 Insert INTO (字典的键) VALUE (字典的值) 由于使用于 mysql,因为安全原因,不想使用+法来构造 其他三种 python 字符串构造方法好像都不行, a.使用% b.使用 format() c.使用 f-string 我没想出来方案,请大神指点迷津

    17 条回复    2020-03-27 19:48:05 +08:00
    todd7zhang
        1
    todd7zhang  
       2020-03-27 17:15:10 +08:00
    d = {'name': 123, 'age': 456}
    keys = d.keys()
    sql = 'insert into (%s) value (%s)' % (','.join('%s' % k for k in keys), ','.join('%%s' for _ in keys))
    cr.execute(sql, tuple(d.values()))
    todd7zhang
        2
    todd7zhang  
       2020-03-27 17:15:56 +08:00
    后面是 %s for_ in keys
    关键是 构造出 'insert into (name, age) values (%s, %s)' 就行了
    Vegetable
        3
    Vegetable  
       2020-03-27 17:26:11 +08:00
    我寻思这加号和直接字符串方法在安全上有区别吗?不都是直接拼接 SQL 吗?
    wuwukai007
        4
    wuwukai007  
       2020-03-27 17:26:38 +08:00 via Android
    没看懂+怎么会不安全,用了多线程吗
    sikong31
        5
    sikong31  
       2020-03-27 17:26:40 +08:00
    def insert(self, table, **kw):
    fields, values = zip(*kw.items())
    fields_str = ','.join(fields)
    values_str = ','.join(['?'] * len(fields))
    sql = f"INSERT INTO {table} ({fields_str}) values ({values_str})"
    self.con.execute(sql, values)
    wysnylc
        6
    wysnylc  
       2020-03-27 17:27:40 +08:00
    注入警告
    xpresslink
        7
    xpresslink  
       2020-03-27 17:32:26 +08:00
    >>> d = {'name': 123, 'age': 456}
    >>> 'insert into table{0} values{1};'.format(tuple(d.keys()),tuple(d.values()))
    "insert into table('name', 'age') values(123, 456);"
    >>>
    xpresslink
        8
    xpresslink  
       2020-03-27 17:37:44 +08:00
    但是不建议一条一条的插入,最好用批量插入,数据量大了效率差万倍。
    建一个插入模板
    >> sql = 'insert into (name, age) values (%s, %s)'
    >> conn.executemany(sql, list(d.values()))
    大多数 python 的 mysql 驱动接口都带 executemany()方法。
    sikong31
        9
    sikong31  
       2020-03-27 17:39:11 +08:00
    @xpresslink 他这是不定长的字典,键多少不固定,批量不了
    ClericPy
        10
    ClericPy  
       2020-03-27 18:05:44 +08:00
    防注入就用框架吧... 我现在用的 databases, 貌似是基于 aiomysql 和 sqlalchemy 的, 直接丢字典进去就行了...
    fzhyzamt
        11
    fzhyzamt  
       2020-03-27 18:21:53 +08:00
    mysql 那几个库好像自带防注入的,只要你不把数据直接 format 到语句里,所以你提的那三种方式没啥区别
    j0shfan
        12
    j0shfan  
    OP
       2020-03-27 19:14:24 +08:00
    @todd7zhang 这样可行,感谢方案
    j0shfan
        13
    j0shfan  
    OP
       2020-03-27 19:15:57 +08:00
    @xpresslink 可以,简洁明了
    j0shfan
        14
    j0shfan  
    OP
       2020-03-27 19:19:10 +08:00
    @sikong31 方案可以,感谢
    j0shfan
        15
    j0shfan  
    OP
       2020-03-27 19:25:39 +08:00
    @xpresslink 感谢提醒
    j0shfan
        17
    j0shfan  
    OP
       2020-03-27 19:48:05 +08:00
    @Trim21 我用了 mysql python 官方连接器,有空我了解下 SQLAlchemy,多谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1367 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:35 · PVG 07:35 · LAX 16:35 · JFK 19:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.