在Connection.execute sqlalchemy中运行UPDATE SET参数化的sql语句

时间:2019-11-11 09:34:23

标签: python mysql sqlalchemy flask-sqlalchemy

我想在flask_sqlalchemy中运行参数化的mysql UPDATE SET语句。由于我不知道应更新哪些列,因此我编写了一个辅助函数来帮助编写该语句。

我的模特

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement= True)
    username = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

助手功能

def run_sql(params):
    # e.g: params = {'username': "testing", "email": "testing@testing.ts", "id": 1}
    id = params.pop("id")
    # params = {'username': "testing", "email": "testing@testing.ts"}
    sets = list(map(lambda col: f"{col}=:{col}", params.keys()))
    # sets = ["username=:username", "email=:email"]
    sets = ", ".join(sets)
    # sets = "username=:username, email=:email"
    params["id"] = id
    # params = {'username': "testing", "email": "testing@testing.ts", "id": 1}
    sql_statement = f"""UPDATE User SET {sets} WHERE id=:id LIMIT 1"""
    # sql_statement = UPDATE User SET username=:username, email=:email WHERE id=:id LIMIT 1
    return  sql_statement

调用助手功能

if __name__ == "__main__":
    conn = engine.connect()
    params = {'username': "testing", "email": "testing@testing.ts", "id": 1}
    sql_statement = run_sql(params)
    conn.execute(sql_statement, params)

运行前面的代码会生成以下异常

"sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ':username, email=:email WHERE id=:id LIMIT 1' at line 1") [SQL: 'UPDATE User SET username=:username, email=:email WHERE id=:id LIMIT 1'] [parameters: {'username': 'testing', 'email': 'testing@testing.ts', 'id': 1}] (Background on this error at: http://sqlalche.me/e/f405)"

SQL语句对我来说很好,所以参数也不错。我想念什么吗?

2 个答案:

答案 0 :(得分:2)

如果要对SQL语句使用:named_parameter格式,则需要使用SQLAlchemy的text方法,然后调用execute对象的Engine方法:

import sqlalchemy as sa

# ...

engine.execute("CREATE TEMPORARY TABLE temp (id varchar(10) PRIMARY KEY)")
sql = sa.text("INSERT INTO temp (id) VALUES (:id)")
params = {'id': 'foo'}
engine.execute(sql, params)

print(engine.execute("SELECT * FROM temp").fetchall())  # [('foo',)]

答案 1 :(得分:2)

绑定参数不是MySQL样式,当您将纯文本传递给engine.execute()时,SQLAlchemy不会在执行查询之前将方言应用于查询。

尝试一下:

engine.execute("SELECT :val", {"val": 1})  # will fail, same as your query

...然后是这个

engine.execute("SELECT %(val)s", {"val": 1})  # will execute

text()包裹查询将使SQLAlchemy处理正确的绑定样式:

from sqlalchemy import text  # or you can use db.text w/ flask-sqlalchemy
engine.execute(text("SELECT :val"), {"val": 1})

要注意的另一件事是,SQLAlchemy将自动为您处理UPDATE查询的构造,同时遵守参数dict中的值,例如:

id_ = 1
params = {'username': "testing", "email": "testing@testing.ts"}
User.__table__.update().values(params).where(id=id_)
# UPDATE user SET username=%(username)s, email=%(email)s WHERE user.id = %(id_1)s

params = {'username': "testing"}
User.__table__.update().values(params).where(id=id_)
# UPDATE user SET username=%(username)s WHERE user.id = %(id_1)s

params = {'username': "testing", "unexpected": "value"}
User.__table__.update().values(params).where(id=id_)
# sqlalchemy.exc.CompileError: Unconsumed column names: unexpected