sqlalchemy 在多个表上加入和排序

sqlalchemy join and order by on multiple tables

我正在使用一个具有如下关系的数据库:

    class Source(Model):
       id = Identifier()

    class SourceA(Source):
       source_id = ForeignKey('source.id', nullable=False, primary_key=True)
       name = Text(nullable=False)

    class SourceB(Source):
       source_id = ForeignKey('source.id', nullable=False, primary_key=True)
       name = Text(nullable=False)

    class SourceC(Source, ServerOptions):
       source_id = ForeignKey('source.id', nullable=False, primary_key=True)
       name = Text(nullable=False)

我想要做的是连接所有表 Source、SourceA、SourceB、SourceC,然后连接 order_by 名称。

对我来说听起来很容易,但我一直在努力解决这个问题,现在我的头开始疼了。此外,我对 SQL 或 sqlalchemy 不是很熟悉,因此浏览了很多文档但无济于事。也许我只是没有看到它。 This 似乎很接近,尽管与比我可用的更新版本相关(见下面的版本)。

我觉得很接近,不是 有什么意义。这是我最近的尝试,在 order_by 调用之前看起来不错。

    Sources = [SourceA,  SourceB, SourceC]
    # list of join on Source
    joins = [session.query(Source).join(source) for source in Sources]
    # union the list of joins
    query = joins.pop(0).union_all(*joins)

据我所知,此时查询似乎是正确的,即 query.all() 有效。所以现在我尝试应用 order_by,它在调用 .all 之前不会抛出错误。

尝试1:我只是使用我想要的属性

    query.order_by('name').all()
    # throws sqlalchemy.exc.ProgrammingError: (ProgrammingError) column "name" does not exist

尝试 2:我只是使用我想要的已定义列属性

    query.order_by(SourceA.name).all()
    # throws sqlalchemy.exc.ProgrammingError: (ProgrammingError) missing FROM-clause entry for table "SourceA"

很明显吗?我错过了什么?谢谢!

版本:

sqlalchemy.版本 = '0.8.1'

(PostgreSQL) 9.1.3

编辑 我正在处理一个需要查询对象句柄的框架。我有一个裸查询似乎可以完成我想要的,但我仍然需要将它包装在一个查询对象中。不确定这是否可能。谷歌搜索...

select = """
    select s.*, a.name from Source d inner join SourceA a on s.id = a.Source_id
    union
    select s.*, b.name from Source d inner join SourceB b on s.id = b.Source_id
    union
    select s.*, c.name from Source d inner join SourceC c on s.id = c.Source_id
    ORDER BY "name";
"""
selectText = text(select)
result = session.execute(selectText)
# how to put result into a query. maybe Query(selectText)? googling...
result.fetchall():

您的第一次尝试听起来没有效果,因为源中没有名称,它是查询的根 table。此外,您的联接后会有多个名称列,因此您需要更加具体。尝试

query.order_by('SourceA.name').all()

至于你的第二次尝试,ServerA是什么?

query.order_by(ServerA.name).all()

可能是打字错误,但不确定是针对 SO 还是您的代码。尝试:

query.order_by(SourceA.name).all()

假设 coalesce 功能足够好,下面的示例应该为您指明方向。一个选项自动创建子列表,而另一个选项是显式的。

这不是您在编辑中指定的查询,但您可以排序(您的原始请求):

def test_explicit():
    # specify all children tables to be queried
    Sources = [SourceA, SourceB, SourceC]
    AllSources = with_polymorphic(Source, Sources)

    name_col = func.coalesce(*(_s.name for _s in Sources)).label("name")
    query = session.query(AllSources).order_by(name_col)
    for x in query:
        print(x)


def test_implicit():
    # get all children tables in the query
    from sqlalchemy.orm import class_mapper
    _map = class_mapper(Source)
    Sources = [_smap.class_
               for _smap in _map.self_and_descendants
               if _smap != _map  # @note: exclude base class, it has no `name`
               ]
    AllSources = with_polymorphic(Source, Sources)

    name_col = func.coalesce(*(_s.name for _s in Sources)).label("name")
    query = session.query(AllSources).order_by(name_col)
    for x in query:
        print(x)