14

我正在使用 pyodbc 查询 SQL Server 数据库

import datetime
import pyodbc    
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db',
                       TrustedConnection=Yes")
cursor = conn.cursor()
ratings = ("PG-13", "PG", "G")
st_dt = datetime(2010, 1, 1)
end_dt = datetime(2010, 12, 31)
cursor.execute("""Select title, director, producer From movies 
                Where rating In ? And release_dt Between ? And ?""", 
                ratings, str(st_dt), str(end_dt))

但我收到以下错误。元组参数是否需要以不同的方式处理?有没有更好的方法来构造这个查询?

('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Line 9: 
  Incorrect syntax near '@P1'. (170) (SQLExecDirectW); 
  [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]
  Statement(s) could not be prepared. (8180)")

更新:

我能够使用字符串格式化运算符让这个查询工作,这并不理想,因为它引入了安全问题。

import datetime
import pyodbc    
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db',
                       TrustedConnection=Yes")
cursor = conn.cursor()
ratings = ("PG-13", "PG", "G")
st_dt = datetime(2010, 1, 1)
end_dt = datetime(2010, 12, 31)
cursor.execute("""Select title, director, producer From movies 
                Where rating In %s And release_dt Between '%s' And '%s'""" % 
                (ratings, st_dt, end_dt))
4

4 回答 4

21

为了扩展拉里的第二个选项 - 动态创建参数化字符串,我成功地使用了以下内容:

placeholders = ",".join("?" * len(code_list))
sql = "delete from dbo.Results where RESULT_ID = ? AND CODE IN (%s)" % placeholders
params = [result_id]
params.extend(code_list)
cursor.execute(sql, params)

给出以下带有适当参数的 SQL:

delete from dbo.Results where RESULT_ID = ? AND CODE IN (?,?,?)
于 2013-05-24T10:07:16.320 回答
18

您不能IN ()使用单个字符串参数参数化子句中的多个值。实现这一目标的唯一方法是:

  1. 字符串替换(就像你做的那样)。

  2. 在表单中构建一个参数化查询,IN (?, ?, . . ., ?)然后为每个占位符传入一个单独的参数。我不是 Python 到 ODBC 的专家,但我想这在 Python 这样的语言中特别容易做到。这更安全,因为您可以获得参数化的全部价值。

于 2011-01-28T03:37:29.670 回答
3

扩展拉里和地理的答案:

ratings = ('PG-13', 'PG', 'G')
st_dt = datetime(2010, 1, 1)
end_dt = datetime(2010, 12, 31)

placeholders = ', '.join('?' * len(ratings))
vars = (*ratings, st_dt, end_dt)
query = '''
    select title, director, producer
    from movies
    where rating in (%s)
       and release_dt between ? and ?
''' % placeholders

cursor.execute(query, vars)

使用占位符,这将返回一个查询:

    select title, director, producer
    from movies
    where rating in (?, ?, ?)
       and release_dt between ? and ?

如果您传入ratings,它将尝试将其所有项目放入一个?. 但是,如果我们传入*ratings,并且其中的每个项目都ratings将在in()子句中占据其位置。因此,我们将元组传递(*ratings, st_dt, end_dt)cursor.execute().

于 2019-09-19T14:34:54.877 回答
2

问题是你的元组。ODBC 连接需要一个字符串来构造查询,并且您正在发送一个 python 元组。请记住,您必须正确引用字符串。我假设您要查找的评分数量会有所不同。可能有更好的方法,但我的 pyodbc 往往简单明了。

尝试以下操作:

import datetime
import pyodbc    
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db',
                       TrustedConnection=Yes")

def List2SQLList(items):
    sqllist = "%s" % "\",\"".join(items)
    return sqllist


cursor = conn.cursor()
ratings = ("PG-13", "PG", "G")
st_dt = datetime(2010, 1, 1)
end_dt = datetime(2010, 12, 31)
cursor.execute("""Select title, director, producer From movies 
                Where rating In (?) And release_dt Between ? And ?""", 
                List2SQLList(ratings), str(st_dt), str(end_dt))
于 2011-01-27T19:01:23.120 回答