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

Moh*_*nka 106 python sql

我有一个python列表,比如l

l = [1,5,8]
Run Code Online (Sandbox Code Playgroud)

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

select name from students where id = |IN THE LIST l|
Run Code Online (Sandbox Code Playgroud)

我该如何做到这一点?

bob*_*nce 97

到目前为止,答案一直在将值模板化为纯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)
Run Code Online (Sandbox Code Playgroud)

  • `','.join(占位符*len(l))`会更短,但仍然可读imho (9认同)
  • @Thiefmaster:是的,在一般情况下必须是`([placeholder]*len(l))`,因为占位符可能是多个字符. (7认同)
  • 阅读这些评论和其他答案,我明白为什么存在如此多的 SQL 注入漏洞。几乎没有人关心(直到他们被pwned)。 (4认同)
  • @bobince 在我的例子中,我分配了一个变量 a='john' 和 b='snow' 并将其存储在名称为 got=['a,b'] 的元组中,并执行了相同的查询。这样做我得到了错误,即类型错误:在字符串格式化过程中并非所有参数都被转换。我该怎么解决它 (2认同)
  • 你为什么要"手工"加入而不是将这项工作留给dbapi?关键是使用元组而不是列表...... (2认同)
  • 基于此答案,这里是适用于*** Python 3.6 ***的单行解决方案:`cursor.execute(f'从其中ID为IN的学生中选择名称({','。join('?'for _ in l})} )',l)`。@bobince,您还应该在解决方案中指出,就避免SQL注入而言,使用`?`是安全的方法。这里有很多容易受到攻击的答案,基本上是将python中的字符串连接起来的答案。 (2认同)

Ami*_*ani 31

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

t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Run Code Online (Sandbox Code Playgroud)

  • 与这里除已接受的答案之外的大多数答案一样,这很容易受到 SQL 注入的影响,因此不应使用。 (14认同)
  • 如@renstrm所述,如果l仅包含一个元素,则此操作将无效,您最终将获得id IN(1,)。这是语法错误。 (9认同)
  • @BaconBits 公平警告,但对于某些 SQL 注入不成问题的应用程序(例如,分析我是唯一用户的数据库),这样做就可以了。 (3认同)

Bla*_*rad 21

你想要的SQL是

select name from studens where id in (1, 5, 8)
Run Code Online (Sandbox Code Playgroud)

如果你想从你可以使用的python构造它

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

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

或者:

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

如果您更喜欢生成器表达式到map函数.

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

select name from studens where id = 1 or id = 5 or id = 8
Run Code Online (Sandbox Code Playgroud)

由...生成

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

  • :-( Python SQLite绑定不支持序列. (2认同)

all*_*yed 21

不要复杂,解决方案很简单.

l = [1,5,8]

l = tuple(l)

params = {'l': l}

cursor.execute('SELECT * FROM table where id in %(l)s',params)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我希望这有帮助!

  • 如果`l`只包含一个元素,那么这将不起作用,你最终会得到`id IN(1,)`.这是语法错误. (7认同)
  • 如果l只包含1个元素,请确保它是一个元组,它会起作用.在我看来,这个解决方案比接受的解决方案更清晰. (3认同)
  • 但是,如果元组为空,它将仍然无法工作,因此在执行查询之前必须进行其他检查。 (2认同)
  • 这对我的 `sqlite3` 不起作用。您针对哪个库进行了测试? (2认同)

gim*_*mel 10

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

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

(谢谢,blair-conrad)

  • 由于此方法不使用数据库参数替换,因此会使您面临 SQL 注入攻击。这里使用的 `%` 只是简单的 Python 字符串格式。 (2认同)

jim*_*ark 6

我喜欢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)
Run Code Online (Sandbox Code Playgroud)

但我注意到了这一点:

placeholders= ', '.join(placeholder for unused in l)
Run Code Online (Sandbox Code Playgroud)

可以替换为:

placeholders= ', '.join(placeholder*len(l))
Run Code Online (Sandbox Code Playgroud)

如果不那么聪明而不那么普遍,我会发现这更直接.这里l需要有一个长度(即引用定义__len__方法的对象),这应该不是问题.但占位符也必须是单个字符.要支持多字符占位符,请使用:

placeholders= ', '.join([placeholder]*len(l))
Run Code Online (Sandbox Code Playgroud)


Sam*_*son 5

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

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

即只需确保您将IN参数作为tuple. 如果是 alist你可以使用= ANY数组语法

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

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


小智 5

只需使用元组函数的内联 if 操作:

query = "Select * from hr_employee WHERE id in " % tuple(employee_ids) if len(employee_ids) != 1 else "("+ str(employee_ids[0]) + ")"
Run Code Online (Sandbox Code Playgroud)