我正在将一些使用 SQLite 的基于 SQLAlchemy2 的代码迁移到 PostgreSQL(SQLAlchemy 2.0.8、psycopg2-binary 2.9.1、Python 3.10、PostgreSQL 15 服务器)。结果令人惊讶:非手动创建的请求中存在语法错误(我很容易想象手动创建的请求中存在错误,但很难想象通过 API 创建的请求而不直接使用 SQL 语言会出现类似的问题)。我将示例改进为一个简约的程序。在这里。
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy import create_engine, select
class Base(DeclarativeBase):
...
class Obj(Base):
__tablename__ = "objects"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(index=True, nullable=False)
def read(dburl: str) -> None:
engine = create_engine(dburl, echo=True)
Base.metadata.create_all(engine)
session = Session(engine)
stmt = select(Obj).where(Obj.name.is_('some_name'))
if session.scalars(stmt).first():
print("Found")
read('sqlite://')
#read('postgresql://user:passwd@HOST:5432/dbname')
当我以初始形式执行程序时,它成功了。当我注释掉 SQLite URL 并取消注释 Postgres URL 时,它会以下列方式失败:
psycopg2.errors.SyntaxError: ERROR: syntax error at or near 'some_name'
LINE 3: WHERE objects.name IS 'some_name'
带参数的请求,根据日志,是:
[SQL: SELECT objects.id, objects.name
FROM objects
WHERE objects.name IS %(name_1)s]
[parameters: {'name_1': 'some_name'}]
对我来说,这个要求似乎很理智。表已成功创建,其结构完全符合预期,但第一个
SELECT
失败。可能是什么原因以及如何解决?
UPD:
已找到修复程序(请参阅我的答案)。但原因还没有,所以我还不会接受我自己的答案。
将
stmt = select(Obj).where(Obj.name.is_('some_name'))
更改为 stmt = select(Obj).where(Obj.name == 'some_name')
即可解决问题。虽然我还是不明白原因。