sql查询中的python列表作为参数


123

我有一个python列表,说我

l = [1,5,8]

我想编写一个SQL查询来获取列表中所有元素的数据,例如

select name from students where id = |IN THE LIST l|

我该如何完成?

Answers:


111

到目前为止,答案一直是将这些值模板化为纯SQL字符串。这对于整数绝对没问题,但是如果我们想对字符串进行处理,则会遇到转义问题。

这是一个使用参数化查询的变体,它对两个都适用:

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

11
','.join(placeholder * len(l))在仍然可读的恕我直言的情况下会短一些
ThiefMaster

7
@Thiefmaster:是的,([placeholder]*len(l))由于占位符可能是多个字符,因此通常情况下必须如此。
bobince

1
在我的情况下,@ bobince我分配了一个变量a ='john'和b ='snow'并将其存储在一个名为get = ['a,b']的元组中,并执行了相同的查询。这样做我得到了错误,即类型错误:不是在字符串格式化期间转换了所有参数。我应该如何解决
TechJhola 2015年

2
为什么要“手工”加入而不是将这项工作留给dbapi?关键是使用元组而不是列表...
Alessandro Dentella

5
基于此答案,这里是适用于Python 3.6 的单行解决方案cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)。@bobince,您还应该在解决方案中指出?,就避免SQL注入而言,使用是安全的方法。这里有很多容易受到攻击的答案,基本上都是将python中的字符串连接起来的答案。
toto_tico

59

最简单的方法是将列表转到tuple第一

t = tuple(l)
query = "select name from studens where id IN {}".format(t)

1
这实际上是正确的答案。我不确定为什么它被忽略了。首先,您设置列表l,然后使用元组,然后将元组传递到查询中。做得好。
MEdwin

11
如@renstrm所述,如果l仅包含一个元素,则此操作将无效,您最终将获得id IN(1,)。这是语法错误。
Doubledown '19

1
@Boris如果你不能保证你的输入始终是一个列表,你可以做类似这样的一个衬垫东西stackoverflow.com/questions/38821586/...传递参数查询之前
阿米尔伊曼尼

10
就像这里的大多数答案(除了已接受的答案)一样,此方法容易受到SQL注入的影响,因此不应使用。
培根片

2
@BaconBits公平警告,但对于不存在SQL注入问题的某些应用程序(例如,对我是唯一用户的数据库进行分析),则可以这样做。
艾琳

26

不要使其复杂化,解决方案很简单。

l = [1,5,8]

l = tuple(l)

params = {'l': l}

cursor.execute('SELECT * FROM table where id in %(l)s',params)

在此处输入图片说明

我希望这可以帮助!!!


10
如果l仅包含一个元素,则此操作将无效,最后得到id IN (1,)。这是语法错误。
renstrm '16

3
如果l仅包含1个元素,请确保它是一个元组并且它将起作用。我认为,这种解决方案比公认的解决方案更清晰。
亚历山德罗·登特拉

2
但是,如果元组为空,它仍然无法工作,因此在执行查询之前必须进行其他检查。
НикитаКонин

2
这对我不起作用sqlite3。您针对哪个库进行了测试?
Nick Chammas

1
好的解决方案,但@renstrm和Никита-Конин是正确的,因为需要对元组是单个元素还是没有元素进行额外检查。
阿妮丝·萨那

23

您想要的SQL是

select name from studens where id in (1, 5, 8)

如果您想从python构造它,可以使用

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'

地图功能将改变列表转换成可以通过使用逗号胶合在一起的字符串列表str.join方法。

或者:

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'

如果您更喜欢生成器表达式而不是map函数。

更新:S. Lott在评论中提到Python SQLite绑定不支持序列。在这种情况下,您可能想要

select name from studens where id = 1 or id = 5 or id = 8

产生者

sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))

2
:-( Python SQLite绑定不支持序列
。– S.Lott

哦?我没意识到 再说一次,我没有意识到我们要使用SQLite绑定解决方案。
布莱尔·康拉德

抱歉,没有建议或暗示SQLite -遗憾的是列表绑定在那里不起作用。
S.Lott

11

string.join用逗号分隔的列表值,并使用format运算符形成查询字符串。

myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))

(谢谢,布莱尔康拉德


2
由于此方法不使用数据库参数替换,因此使您容易受到SQL注入攻击。在%这里使用的存在,只是普通的Python字符串格式化。
Nick Chammas

8

我喜欢bobince的回答:

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

但是我注意到了这一点:

placeholders= ', '.join(placeholder for unused in l)

可以替换为:

placeholders= ', '.join(placeholder*len(l))

如果不太聪明和不太笼统,我会觉得这更直接。这里l需要有一个长度(即,引用一个定义__len__方法的对象),这应该不是问题。但是占位符也必须是单个字符。要支持多字符占位符使用:

placeholders= ', '.join([placeholder]*len(l))

2

@umount答案的解决方案,因为它用一个元素的元组中断,因为(1,)不是有效的SQL。

>>> random_ids = [1234,123,54,56,57,58,78,91]
>>> cursor.execute("create table test (id)")
>>> for item in random_ids:
    cursor.execute("insert into test values (%d)" % item)
>>> sublist = [56,57,58]
>>> cursor.execute("select id from test where id in %s" % str(tuple(sublist)).replace(',)',')'))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]

sql字符串的其他解决方案:

cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))

5
由于sql注入,这不是更好的解决方案。
阿努拉格

2
placeholders= ', '.join("'{"+str(i)+"}'" for i in range(len(l)))
query="select name from students where id (%s)"%placeholders
query=query.format(*l)
cursor.execute(query)

这应该可以解决您的问题。


2

如果您将PostgreSQL与Psycopg2库一起使用,则可以让其元组适应为您完成所有转义和字符串插值,例如:

ids = [1,2,3]
cur.execute(
  "SELECT * FROM foo WHERE id IN %s",
  [tuple(ids)])

即只需确保您将IN参数作为传递tuple。如果是,则list可以使用= ANY数组语法

cur.execute(
  "SELECT * FROM foo WHERE id = ANY (%s)",
  [list(ids)])

请注意,这两个都将变成相同的查询计划,因此您应该只使用较容易的那个。例如,如果您的列表位于一个元组中,则使用前者;如果它们存储在列表中,则使用后者。


1

例如,如果要使用sql查询:

select name from studens where id in (1, 5, 8)

关于什么:

my_list = [1, 5, 8]
cur.execute("select name from studens where id in %s" % repr(my_list).replace('[','(').replace(']',')') )


1
l = [1] # or [1,2,3]

query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)

:var符号似乎简单。(Python 3.7)


0

这使用参数替换并处理单个值列表的情况:

l = [1,5,8]

get_operator = lambda x: '=' if len(x) == 1 else 'IN'
get_value = lambda x: int(x[0]) if len(x) == 1 else x

query = 'SELECT * FROM table where id ' + get_operator(l) + ' %s'

cursor.execute(query, (get_value(l),))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.