【问题标题】:Sqlalchemy: bulk correlated update to link tablesSqlalchemy:链接表的批量相关更新
【发布时间】:2013-10-14 23:45:54
【问题描述】:

我有两个相关的表已经填充了数据(使用 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 的尝试没有成功。

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

【问题讨论】:

    标签: python sqlite orm sqlalchemy correlated


    【解决方案1】:

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

    大多数表达式 API 都基于 SQLAlchemy 表对象和列。这些表可通过映射类的__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 ?)
    

    【讨论】:

    • 感谢您的解决方案和解释! 'select... where' 方法工作正常。但是,“查询...过滤器”方法会引发 AttributeError:'Query' object has no attribute 'self_group'。我很好奇为什么。再次 - 非常感谢帮助!
    • 实际上,我不确定这是怎么回事。我曾一度以为我让它工作了,但我想我没有(得到相同的错误消息)。无论如何,使用表达式 API 是可行的,所以你可以坚持下去。
    猜你喜欢
    • 2017-06-11
    • 1970-01-01
    • 2019-08-17
    • 2013-05-19
    • 2015-12-04
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 2016-11-29
    相关资源
    最近更新 更多