Python 动态SQL WHERE子句生成

Python 动态SQL WHERE子句生成,python,sql,sqlite,language-agnostic,sql-injection,Python,Sql,Sqlite,Language Agnostic,Sql Injection,作为记录,我使用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

作为记录,我使用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
稍后我可能需要添加多个列和条件

还有更好的主意吗

编辑: 看起来不对的是,我正在从字符串动态构造SQL。这通常不是最好的方法。SQL注入attacs,需要正确转义字符串。我无法使用占位符,因为某些值为无,不需要处于WHERE子句条件下。

您确实不想使用字符串格式来包含值。通过SQL参数将其留给数据库API

使用参数可以:

  • 让数据库有机会准备语句并重用查询计划以获得更好的性能
  • 省去了正确转义值的麻烦(包括避免允许SQL转义和SQL注入攻击)
从SQLLite开始,我将返回一个语句和一个带参数的字典:

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
然后将两者都传递给游标。执行():

SQL生成很快就会变得复杂,您可能需要查看以执行生成

例如,您可以生成:

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

查询
对象可以对其应用附加过滤器,对其进行排序、分组、用作其他查询的子选择、连接并最终发送以执行,此时SQLAlchemy会将其转换为适合您所连接的特定数据库的SQL。

只是为了完整性。我发现pypika库非常方便(如果允许库的话):

它允许像这样构造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)

感谢SQLAlchemy链接。但这超出了范围。仅限标准/内置模块。@Ayman:那么至少要使用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)