SQLAlchemy 单个查询从两个表中返回列

Posted

技术标签:

【中文标题】SQLAlchemy 单个查询从两个表中返回列【英文标题】:SQLAlchemy single query to return columns from two tables 【发布时间】:2021-07-07 00:13:09 【问题描述】:

有没有办法使用一条 SQLAlchemy 查询语句在 Index 表中查找相应的 ID 并从 DimIndexPrice 表中过滤这些行而不使用两条语句?

我觉得我没有通过使用两个语句来使用 SQLAlchemy 的全部表现力。我是 SQL 的初学者,但 union 和 join 在这里没有意义,所以也许这是正确的设计模式。

q = 'VOO'
first_query = db_session.query(Index).filter_by(Symbol=q).first()
second_query = db_session.query(DimIndexPrice).filter_by(IndexID=first_query.ID)

class Index(Base):

    __tablename__ = 'Index'

    ID = Column(Integer, primary_key=True, autoincrement=True)
    Symbol = Column(String(4), unique=True, nullable=False)
    FundName = Column(String(120), unique=True, nullable=False)

    def __init__(self, Symbol, FundName):
        self.Symbol = Symbol
        self.FundName = FundName

    def __repr__(self):
        return '<Index %r>' % (self.Symbol)


class DimIndexPrice(Base):

    __tablename__ = 'DimIndexPrice'

    ID = Column(Integer, primary_key=True, autoincrement=True)
    IndexID = Column(Integer, ForeignKey('Index.ID'), nullable=False)
    Date = Column(Date(), nullable=False)
    Open = Column(Float, nullable=False)
    High = Column(Float, nullable=False)
    Low =Column(Float, nullable=False)
    Close = Column(Float, nullable=False)
    CloseAdjusted = Column(Float, nullable=False)
    Volume = Column(Integer, nullable=False)
    DividendAmount = Column(Float, nullable=False)
    SplitCoefficient = Column(Float, nullable=False)

    def __init__(self,
                 IndexID,
                 Date,
                 Open,
                 High,
                 Low,
                 Close,
                 CloseAdjusted,
                 Volume,
                 DividendAmount,
                 SplitCoefficient):
        self.IndexID = IndexID
        self.Date = Date
        self.Open = Open
        self.High = High
        self.Low = Low
        self.Close = Close
        self.CloseAdjusted = CloseAdjusted
        self.Volume = Volume
        self.DividendAmount = DividendAmount
        self.SplitCoefficient = SplitCoefficient

    def __repr__(self):
        return '<DimIndexPrice %r %s>' % (self.IndexID, self.Date)

【问题讨论】:

这似乎是一个 JOIN 确实是正确的做法 @sabik 需要解释一下吗?我需要查询第一个表以获取输入的 ID,然后在第二个表中按此 ID 进行过滤。 是的,这就是 JOIN 的作用 在ID上JOIN两个表,然后在Symbol上过滤 数据库引擎会根据需要自动交换操作顺序以提高效率 【参考方案1】:

使用@sabik 的回答和一些反复试验,我得到了我想要的结果。我不确定这是否是最佳实践,或者为什么.filter 可以使用.join.filter_by 不能,或者为什么需要使用== 而不是= 但它有效。请参阅the docs,但它们对我来说很神秘。

combined_query2 = db_session.query(DimIndexPrice).join(Index, DimIndexPrice.IndexID == Index.ID).filter(Index.Symbol==q)

我在下面使用了输出原始 SQL,这有助于故障排除

from sqlalchemy.dialects import sqlite
print(combined_query2.statement.compile(dialect=sqlite.dialect()))

【讨论】:

【参考方案2】:

这正是 JOIN 的作用:

combined_query = Index.query.filter_by(Symbol=q).join(DimIndexPrice)

由于您设置了 ForeignKey,您无需告诉它要加入哪些列;否则,您可以指定:.join(DimIndexPrice, Symbol.c.ID == DimIndexPrice.c.IndexID)

如果需要,数据库引擎会自动交换操作顺序以提高效率。

另见this answer

【讨论】:

阅读文档后,我找到了有关为什么 filter_by 需要放在首位的信息。您的combined_query 中有一个类型,它应该是Index.ID 而不是Symbol.c.IDc 不需要使用。 combined_query[0].__dict__ 仅返回 Index 表的列。由于我正在过滤 Index 表但需要 DimIndexPrice 列,我应该使用联合,对吧? JOIN 合并列; UNION 合并行

以上是关于SQLAlchemy 单个查询从两个表中返回列的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 使用单个查询更新和更改两个表中的少量列记录

在一个查询Access数据库中从具有不同字段的两个不同表中选择列

单个查询从具有不同列的多个表中获取记录

在 sqlalchemy 中计算子查询

SqlAlchemy ORM - 在查询时限制列(选择) - column_property

如何根据单个表中的两个列值获取 1 条记录?