为了记录,我正在使用Python和SQLlite。我有一个生成我需要的SQL的工作函数,但它似乎不正确。
def daily(self, host=None, day=None):
sql = "SELECT * FROM daily WHERE 1"
if host:
sql += " AND host = '%s'" % (host,)
if day:
sql += " AND day = '%s'" % (day,)
return sql
我可能需要稍后添加多个列和条件。
有更好的想法吗?
修改 看起来不正确的是我正在从Strings动态构建SQL。这通常不是最好的方法。 SQL注入attacs,需要正确转义字符串。我不能使用占位符,因为某些值为None,并且不需要处于WHERE子句条件中。
答案 0 :(得分:10)
您确实不想使用字符串格式来包含值。通过SQL参数将其保留到数据库API。
使用参数:
从SQLLite supports named SQL parameters开始,我将返回一个带有参数的语句和字典:
def daily(self, host=None, day=None):
sql = "SELECT * FROM daily"
where = []
params = {}
if host is not None:
where.append("host = :host")
params['host'] = host
if day is not None:
where.append("day = :day")
params['day'] = day
if where:
sql = '{} WHERE {}'.format(sql, ' AND '.join(where))
return sql, params
然后将两个传递给cursor.execute()
:
cursor.execute(*daily(host, day))
SQL生成变得很复杂快速,您可能希望查看SQLAlchemy core来代替生成。
对于您的示例,您可以生成:
from sqlalchemy import Table, Column, Integer, String, Date, MetaData
metadata = MetaData()
daily = Table('daily', metadata,
Column('id', Integer, primary_key=True),
Column('host', String),
Column('day', Date),
)
from sqlalchemy.sql import select
def daily(self, host=None, day=None):
query = select([daily])
if host is not None:
query = query.where(daily.c.host == host)
if day is not None:
query = query.where(daily.c.day == day)
return query
query
对象可以应用其他过滤器,排序,分组,用作其他查询的子选择,加入并最终发送执行,此时SQLAlchemy将此变为适合特定的SQL您要连接的数据库。
答案 1 :(得分:1)
仅出于完整性考虑。我发现pypika库非常方便(如果允许使用库):
https://pypika.readthedocs.io/en/latest/index.html
它允许构造如下的sql查询:
from pypika import Query
q = Query._from('daily').select('*')
if host:
q = q.where('host' == host)
if day:
q = q.where('day' == day)
sql = str(q)