1

我有两个相关的表已经填充了数据(使用 SQLAlchemy ORM)。但是,目前还没有链接各个记录,即外键列是空的。我需要根据不同列的匹配来批量更新外键列。

为了显示:

class Location(Base):
    __tablename__ = 'locations'
    id = Column(Integer, primary_key=True)
    x = Column(Float)
    y = Column(Float)


class Stopover(Base):
    __tablename__ = 'stopovers'
    id = Column(Integer, primary_key=True)
    x = Column(Float)
    y = Column(Float)
    location_id = Column(Integer, ForeignKey("locations.id"))
    location = relationship("Location", backref=backref("stopovers"))

因此,基本上,我需要通过匹配“x”和“y”列,将 20,000 多个“中途停留”记录中的每一个与“位置”相关联——即批量更新 location_id 列。

此代码正确生成 _location_id_:

for stpvr in session.query(Stopovers).all():
       stpvr.location_id = session.query(Location.id).\
                           filter_by(x=stpvr.x).\
                           filter_by(y=stpvr.y).one()[0]
       session.commit()

但是,它似乎不起作用 - 通过 Sqliteman 探索数据库显示 location_ids 尚未更新。此外,我猜肯定有一种更优雅的方式来解决这个问题。

在文档中,我发现相关更新最接近我正在寻找的内容。但是,文档仅引用 SQL 表达式语言,而我使用的是 ORM。我是 SQLAlchemy 的新手,我尝试将文档转换为 ORM 并没有成功。

对于找到执行此批量更新的最优雅方式的任何帮助,我将不胜感激。提前致谢。

4

1 回答 1

3

SQLAlchemy 分层工作。在基础层,SQLAlchemy 提供了诸如使用各种数据库驱动程序的数据库统一接口和连接池实现之类的东西。在此之上是 SQL 表达式语言,允许您使用 Python 对象定义数据库的表和列,然后使用这些对象使用 SQLAlchemy 提供的 API 创建 SQL 表达式。然后是 ORM。ORM 建立在这些现有层之上,因此即使您使用 ORM,您仍然可以下拉使用表达式 API。使用声明性模型(建立在 ORM 之上),您甚至比这更高。

大多数表达式 API 基于 SQLAlchemy 表对象和列。表可通过__table__映射类的属性访问,列可用作映射类的属性。因此,即使您处于声明级别,您仍然可以在使用您使用声明映射的模型时利用那里可用的大部分内容。因此,示例相关查询...

>>> stmt = select([addresses.c.email_address]).\
...             where(addresses.c.user_id == users.c.id).\
...             limit(1)
>>> conn.execute(users.update().values(fullname=stmt)) 

__table__...可以通过使用属性和声明列转换为声明性 ORM 模型...

>>> stmt = select([Addresses.email_address]).\
...             where(Addresses.user_id == Users.id).\
...             limit(1)
>>> conn.execute(Users.__table__.update().values(fullname=stmt)) 

这是我相信您的相关查询的样子..

stmt = select([Location.id]).\
    where(and_(Location.x==Stopover.x, Location.y==Stopover.y)).limit(1)

conn.execute(Stopover.__table__.update().values(location_id=stmt)

生成的 SQL:

UPDATE stopovers SET location_id=(SELECT locations.id 
FROM locations 
WHERE locations.x = stopovers.x AND locations.y = stopovers.y
LIMIT ? OFFSET ?)
于 2013-10-08T08:37:34.107 回答