交替SQL查询

时间:2018-04-04 14:16:49

标签: python python-3.x sqlite

我正在寻找一种实现交替SQL查询的方法 - 即允许我根据不同列过滤条目的功能。请看以下示例:

el=[["a","b",1],["a","b",3]]    

def save_sql(foo):
    with sqlite3.connect("fn.db") as db:
        cur=db.cursor()
        cur.execute("CREATE TABLE IF NOT EXISTS et"
                    "(var1 VARCHAR, var2 VARCHAR, var3 INT)")
        cur.executemany("INSERT INTO et VALUES "
                        "(?,?,?)", foo)
        db.commit()

def load_sql(v1,v2,v3): 
    with sqlite3.connect("fn.db") as db:
        cur=db.cursor()
        cur.execute("SELECT * FROM et WHERE var1=? AND var2=? AND var3=?", (v1,v2,v3))
        return cur.fetchall()

save_sql(el)

现在,如果我使用load_sql("a","b",1),它会起作用。但是假设我只想查询第一列和第三列,即load_sql("a",None,1)None仅用作占位符)或仅查询最后一列load_sql(None,None,5),这不起作用。

当然可以使用if语句检查函数调用中提供的变量,但是在列数较大的表中,这可能会变得混乱。

有没有好办法呢?

2 个答案:

答案 0 :(得分:2)

如果load_sql()接受任意数量的关键字参数,其中关键字参数名称将对应于列名称,该怎么办?这些方面的东西:

def load_sql(**values): 
    with sqlite3.connect("fn.db") as db:
        cur = db.cursor() 

        query = "SELECT * FROM et"
        conditions = [f"{column_name} = :{column_name}" for column_name in values]

        if conditions:
            query = query + " WHERE " + " AND ".join(conditions)
        cur.execute(query, values)
        return cur.fetchall()

请注意,这里我们相信关键字参数名称是有效的和现有列名(并将它们字符串格式化为查询),这可能会被用作SQL注入攻击向量。

作为旁注,我不能停下来,但认为这对于实际的ORM来说就像是一个重新发明的步骤。查看Python和数据库之间的轻量级PonyORMPeewee抽象层。

答案 1 :(得分:2)

如果你希望你的SQL语句保持消毒/安全,它将不可避免地变得混乱,但只要你控制你的功能签名,它就可以保持相当安全,例如:

def load_sql(var1, var2, var3):
    fields = dict(field for field in locals().items() if field[1] is not None)
    query = "SELECT * FROM et"
    if fields:  # if at least one field is not None:
        query += " WHERE " + " AND ".join((k + "=?" for k in fields.keys()))
    with sqlite3.connect("fn.db") as db:
        cur = db.cursor()
        cur.execute(query, fields.values())
        return cur.fetchall()

您可以使用load_sql(**kwargs)替换函数签名,然后使用kwargs.items()代替locals.items(),以便您可以传递任意列名,但这可能非常危险,当然不建议使用