动态SQL WHERE子句生成

Aym*_*man 4 python sql language-agnostic sqlite 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 sql
Run Code Online (Sandbox Code Playgroud)

我可能需要稍后添加多个列和标准.

有更好的想法吗?

编辑: 看起来不正确的是我正在从Strings动态构建SQL.这通常不是最好的方法.SQL注入attacs,需要正确转义字符串.我不能使用占位符,因为某些值是None,并且不需要在WHERE子句条件中.

Mar*_*ers 12

真的不想使用字符串格式来包含值.通过SQL参数将其保留到数据库API.

使用参数你:

  • 为数据库提供准备语句的机会,并重用查询计划以获得更好的性能.
  • 保存自己正确逃避价值的麻烦(包括避免允许SQL转义和SQL注入攻击).

由于SQLLite 支持命名的SQL参数,我将返回一个语句和一个带参数的字典:

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

然后将两者传递给cursor.execute():

cursor.execute(*daily(host, day))
Run Code Online (Sandbox Code Playgroud)

SQL生成变得复杂,你可能想看看SQLAlchemy的核心做代代替.

对于您的示例,您可以生成:

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

query对象可以应用其他过滤器,排序,分组,用作其他查询的子选择,加入并最终发送执行,此时SQLAlchemy将此变为适合您要连接的特定数据库的SQL.