Sqlalchemy:链接表的批量相关更新

时间:2013-10-08 07:02:33

标签: python sqlite orm sqlalchemy correlated

我有两个已填充数据的相关表(使用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尚未更新。此外,我猜测必须有更优雅的方式来解决这个问题。

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

如果您能找到执行此批量更新的最佳方式,我将不胜感激。提前谢谢。

1 个答案:

答案 0 :(得分:3)

SQLAlchemy在图层中工作。在基础层,SQLAlchemy使用各种数据库驱动程序和连接池实现为数据库提供统一接口等内容。上面是一个SQL表达式语言,允许您使用Python对象定义数据库的表和列,然后使用这些对象使用SQLAlchemy为您提供的API创建SQL表达式。然后是ORM。 ORM构建在这些现有层上,因此即使您使用ORM,您仍然可以下拉以使用表达式API。使用声明性模型(基于ORM构建),您的级别甚至高于该级别。

大多数表达式API都基于SQLAlchemy Table对象和列。表可以通过映射类上的__table__属性访问,列可用作映射类的属性。因此,即使您处于声明级别,在使用使用声明性映射的模型时,仍然可以利用您可用的大部分内容。那么,example correlated query ......

>>> 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 ?)