多次传递此变量的有效方法

Efficient way to pass this variable multiple times

我在 Python 中使用 Pyodbc 来 运行 一些 SQL 查询。我正在处理的实际上比这更长,但是这个例子捕捉到了我正在尝试做的事情:

connection = pyodbc.connect(...)
cursor = connection.cursor(...)

dte = '2018-10-24'

#note the placeholders '{}'
query = """select invoice_id
    into #output 
    from table1 with (nolock) 
    where system_id = 'PrimaryColor' 
    and posting_date = '{}' 

    insert into #output
    select invoice_id
    from table2 with (nolock)
    where system_id = 'PrimaryColor'
    and posting_date = '{}'"""

#this is where I need help as explained below
cursor.execute(query.format(dte, dte))

output = pd.read_sql("""select *
                 from #output"""
                 , connection)

在上面,因为只有两个 '{}',我将 dte 传递给 query.format() 两次。但是,在我使用的更复杂的版本中,我有 19 个 '{}',所以我想这意味着我需要将 'dte' 传递给 'query.format{}' 19 次。我尝试将其作为列表传递,但没有用。将变量传递给函数时,我真的需要将变量写出 19 次吗?

我同意评论,pandas.read_sql 有一个参数参数可以防止 sql 注入。

请参阅 this post 以了解如何根据数据库使用它。

Pyodbc 在执行方法上有相同的参数。

# standard 
cursor.execute("select a from tbl where b=? and c=?", (x, y))

# pyodbc extension 
cursor.execute("select a from tbl where b=? and c=?", x, y)

回答最初的问题,即使构建 SQL 查询是不好的做法:

Do I really need to write out the variable 19 times when passing it to the function?

你当然不知道 :

query = """select invoice_id
into #output 
from table1 with (nolock) 
where system_id = 'PrimaryColor' 
and posting_date = '{dte}' 

insert into #output
select invoice_id
from table2 with (nolock)
where system_id = 'PrimaryColor'
and posting_date = '{dte}'""".format(**{'dte': dte})

或:

query = """select invoice_id
into #output 
from table1 with (nolock) 
where system_id = 'PrimaryColor' 
and posting_date = '{0}' 

insert into #output
select invoice_id
from table2 with (nolock)
where system_id = 'PrimaryColor'
and posting_date = '{0}'""".format(dte)

Python 3.6+ :

query = f"""select invoice_id
into #output 
from table1 with (nolock) 
where system_id = 'PrimaryColor' 
and posting_date = '{dte}' 

insert into #output
select invoice_id
from table2 with (nolock)
where system_id = 'PrimaryColor'
and posting_date = '{dte}'"""

注意 f 在 """ ... "" 之前的用法

考虑使用 UNION ALL 查询来避免临时 table 需求和 parameterization 在其中设置 qmark 占位符并在后续步骤中将值绑定到它们。并且相同的值将参数 list/tuple 乘以所需的数字:

dte = '2018-10-24'

# NOTE THE QMARK PLACEHOLDERS
query = """select invoice_id    
           from table1 with (nolock) 
           where system_id = 'PrimaryColor' 
             and posting_date = ? 

           union all

           select invoice_id
           from table2 with (nolock)
           where system_id = 'PrimaryColor'
             and posting_date = ?"""

output = pd.read_sql(query, connection, params=(dte,)*2)