将表名插入查询会产生sqlite3.OperationalError:near"?":语法错误

Cry*_*rus 27 python sqlite python-2.7

我想动态选择在SQL查询中使用哪个表,但我只是不断收到错误,但我正在尝试格式化它.也试过%s而不是?.

有什么建议?

group_food = (group, food)
group_food_new = (group, food, 1)

with con:

    cur = con.cursor() 
    tmp = cur.execute("SELECT COUNT(Name) FROM (?) WHERE Name=?", group_food)

    if tmp == 0:
        cur.execute("INSERT INTO ? VALUES(?, ?)", group_food_new)
    else: 
        times_before = cur.execute("SELECT Times FROM ? WHERE Name=?", group_food)
        group_food_update = (group, (times_before +1), food)

        cur.execute("UPDATE ? SET Times=? WHERE Name=?", group_food_update)
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 45

您不能将SQL参数用作SQL对象中的占位符; 使用SQL参数的原因之一是转义该值,以便数据库永远不会将内容误认为是数据库对象.

您必须单独插入数据库对象; 通过加倍任何"双引号参数并使用来转义您的标识符

cur.execute('SELECT COUNT(Name) FROM "{}" WHERE Name=?'.format(group.replace('"', '""')), (food,))
Run Code Online (Sandbox Code Playgroud)

和

cur.execute('INSERT INTO "{}" VALUES(?, ?)'.format(group.replace('"', '""')), (food, 1))
Run Code Online (Sandbox Code Playgroud)

和

cur.execute('UPDATE "{}" SET Times=? WHERE Name=?'.format(group.replace('"', '""')),
            (times_before + 1, food))
Run Code Online (Sandbox Code Playgroud)

在".."双引号是有正确丹麦的标识,即使该标识也是一个有效的关键字; "名称中的任何现有字符必须加倍; 这也有助于去除SQL注入尝试.

但是,如果您的对象名称是用户来源的,则必须对对象名称进行自己的(严格的)验证,以防止SQL注入攻击.在这种情况下,始终针对现有对象验证它们.

您应该考虑使用像SQLAlchemy这样的项目来生成SQL; 它可以处理验证对象名称并严格保护您免受SQL注入风险.它可以预先加载您的表定义,以便知道哪些名称是合法的:

from sqlalchemy import create_engine, func, select, MetaData

engine = create_engine('sqlite:////path/to/database')
meta = MetaData()
meta.reflect(bind=engine)
conn = engine.connect()

group_table = meta.tables[group]  # can only find existing tables
count_statement = select([func.count(group_table.c.Name)], group_table.c.Name == food)
count, = conn.execute(count_statement).fetchone()
if count:
    # etc.
Run Code Online (Sandbox Code Playgroud)

  • @colminator:完全是。否则,将会有一个巨大的安全漏洞,有人会在其中添加'';删除表值--`,或其他类似的恶作剧。这是使用SQL参数的主要原因之一(始终使用SQL参数,这是安全的做法!)。 (3认同)
  • 啊!所以'?' 占位符仅用于SQL *值*-不能用于SQL表名称等? (2认同)
  • @colminator:不,对象名称确实无法使用参数。使用像 SQLAlchemy 这样的 SQL 生成器或 [PsycoPG `sql` 模块](http://initd.org/psycopg/docs/sql.html) 来完成这样的任务。 (2认同)
  • @HelloGoodbye:因为参数的用例是转义数据,并且没有简单的方法来检测某些东西是对象名称。例如,您无法从上下文中确定某些东西是否用作数据或对象名称。例如,`WHERE colname = ?` 可以采用对象名称和数据。 (2认同)