【问题标题】:sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) syntax error at or near ":"sqlalchemy.exc.ProgrammingError:(psycopg2.ProgrammingError)在“:”或附近出现语法错误
【发布时间】:2018-04-21 18:54:36
【问题描述】:

这是我的查询:

QUERY = """
        UPDATE my_table
        SET
            my_prop=:foo
        WHERE hello='world'
"""

我这样执行语句:

sqlalchemy_engine.execute(QUERY, foo='bar')

当我这样做时,我收到以下错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) syntax error at or near ":"
UPDATE my_table\n        SET\n            my_prop.foo = :foo
                                                         ^

在将值传递给 SQL Alchemy 执行之前,我从未遇到过问题。我做错了什么?

【问题讨论】:

  • 这不是您在psycopg2 中使用参数的方式。另外,您还想通过将表名设置为其他名称来做什么?
  • 对不起,是要设置一列。请参阅编辑。

标签: python postgresql sqlalchemy


【解决方案1】:

在将值传递给 SQLAlchemy 执行之前,我从未遇到过问题。我做错了什么?

您之前可能使用过Session.execute(),而不是Engine.execute()。前者使用text() 构造自动包装SQL 字符串,或者至少它的行为如此,这是这里的关键;是text() 提供独立于DB-API 驱动程序的绑定参数/占位符处理。没有它,您就会随心所欲地使用 DB-API,as noted by Craig Ringer in their answer

因此,为了直接将 :name 样式占位符与引擎一起使用,只需使用 text() 包装您的查询:

sqlalchemy_engine.execute(text(QUERY), foo='bar')

请注意,SQLAlchemy 应用程序的引擎 is the starting point 和一切都建立在它之上,因此这可能是一个不执行自动包装而另一个执行的原因。 Session 是更高级别的抽象。

【讨论】:

    【解决方案2】:

    psycopg2 不支持:named 参数。 The Python DB-API spec 允许 :named 参数与 paramstyle = 'named',但 psycopg2 使用:

    >>> import psycopg2
    >>> psycopg2.paramstyle
    'pyformat'
    

    as documented in the psycopg2 docs.

    可惜的是 Python 的 DB-API 允许多种参数样式,但就是这样。一些驱动程序似乎支持将 paramstyle 更改为 DB-API 扩展。但看起来psycopg2 不是其中之一:

    >>> psycopg2.paramstyle = 'named'
    >>> psycopg2.paramstyle
    'named'
    >>> cur.execute("SELECT :a, :b, :c", {'a': 1, 'b': 2, 'c': 3})
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    psycopg2.ProgrammingError: syntax error at or near ":"
    LINE 1: SELECT :a, :b, :c
    
    >>> conn.rollback()
    >>> cur.execute("SELECT %(a)s, %(b)s, %(c)s", {'a': 1, 'b': 2, 'c': 3})
    >>> 
    

    因此,如果您以前见过 :param 样式参数起作用,那是因为某些外层(可能是 SQLAlchemy)正在为您调整查询。快速查看SQLAlchemy docs 表明it may do just that

    您猜测,您正在使用当前代码绕过 SQLAlchemy 方言层。但是我真的不知道 SQLAlchemy...

    【讨论】:

    • 最后缺少的只是 QUERY 的 text() 包装器,它将以独立于 DB-API 的方式处理 :name 样式。某些方法(例如 Session.execute())实际上会自动执行此操作,但 Engine.execute() 并非如此。
    猜你喜欢
    • 2020-08-20
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    相关资源
    最近更新 更多