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)
我正在使用一个具有如下关系的数据库:
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)