一尘不染

使用MySQLdb执行“ SELECT…WHERE…IN…”

mysql

我在从Python内部执行某些SQL时遇到了问题,尽管类似的SQL在mysql命令行中也能正常工作。

该表如下所示:

mysql> SELECT * FROM foo;
+-------+-----+
| fooid | bar |
+-------+-----+
|     1 | A   | 
|     2 | B   | 
|     3 | C   | 
|     4 | D   | 
+-------+-----+
4 rows in set (0.00 sec)

我可以从mysql命令行执行以下SQL查询,而不会出现问题:

mysql> SELECT fooid FROM foo WHERE bar IN ('A','C');
SELECT fooid FROM foo WHERE bar IN ('A','C');
+-------+
| fooid |
+-------+
|     1 | 
|     3 | 
+-------+
2 rows in set (0.00 sec)

但是,当我尝试在Python中执行相同操作时,没有任何行,而我希望有2行:

import MySQLdb
import config
connection=MySQLdb.connect(
    host=config.HOST,user=config.USER,passwd=config.PASS,db='test')
cursor=connection.cursor()

sql='SELECT fooid FROM foo WHERE bar IN %s'
args=[['A','C']]
cursor.execute(sql,args)
data=cursor.fetchall()
print(data)
# ()

所以,问题是:应该如何Python代码进行修改,以选择那些fooidS其中bar('A','C')

顺便说一句,我注意到,如果我切换的角色barfooid,我可以得到代码选择那些barS其中fooid(1,3)成功的。我不明白为什么一个这样的查询(下面)有效,而另一个(上面)却无效。

sql='SELECT bar FROM foo WHERE fooid IN %s'
args=[[1,3]]
cursor.execute(sql,args)
data=cursor.fetchall()
print(data)
# (('A',), ('C',))

绝对要清楚,这是foo表的创建方式:

mysql> DROP TABLE IF EXISTS foo;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE `foo` (
          `fooid` int(11) NOT NULL AUTO_INCREMENT,
          `bar` varchar(10) NOT NULL,
          PRIMARY KEY (`fooid`));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT into foo (bar) values ('A'),('B'),('C'),('D');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

编辑 :当我启用通用查询日志,mysqld -l /tmp/myquery.log 我看到

mysqld, Version: 5.1.37-1ubuntu5.5-log ((Ubuntu)). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
110101 11:45:41     1 Connect   unutbu@localhost on test
            1 Query set autocommit=0
            1 Query SELECT fooid FROM foo WHERE bar IN ("'A'", "'C'")
            1 Query SELECT bar FROM foo WHERE fooid IN ('1', '3')
            1 Quit

实际上,似乎在A和周围放置了过多的引号C

感谢@Amber的评论,我更好地了解出了什么问题。MySQLdb将参数化参数转换['A','C']("'A'","'C'")

有没有一种方法可以使用INSQL语法进行参数化查询?还是必须手动构造SQL字符串?


阅读 258

收藏
2020-05-17

共1个答案

一尘不染

这是一个类似的解决方案,我认为在SQL中建立%s字符串列表更有效:

list_of_ids直接使用:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

这样,您就不必引用自己的报价,并避免各种SQL注入。

请注意,数据(list_of_ids)作为参数直接进入mysql的驱动程序(不在查询文本中),因此没有注入。您可以在字符串中保留所需的任何字符,而无需删除或引用字符。

2020-05-17