我有一个表示层次结构的数据库表,这意味着它有一个自引用外键。我想根据他们拥有的孩子数来对对象进行排序。
问题是我既不知道如何进行适当的自联接,也不知道如何在原始查询中询问子集合的计数。结果是我不得不求助于检索子项,获取子集合长度,并在Python中对结果进行排序。
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
engine = create_engine("...")
Session = sessionmaker(bind=engine)
session = Session()
class Variable(Base):
__tablename__ = 'variable'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('variable.id'))
parent = relationship('Variable', remote_side=[id], backref="children")
# Works fine
for v in session.query(Variable).all():
print(len(v.children))
# Works fine
for v in session.query(Variable.id).all():
print(v)
# AttributeError: type object 'Variable' has no attribute 'children'
for v in session.query(func.count(Variable.children)).all():
print(v)
# AttributeError: type object 'Variable' has no attribute 'children'
for v in session.query(Variable.children).all():
print(v)
似乎认为它不知道children
,但仅限于某些情况。作为实验,我尝试明确添加children
:
children = relationship('Variable', backref="parent")
我收到以下错误:
Error creating backref 'parent' on relationship 'Variable.children': property of that name exists on mapper 'Mapper|Variable|variable'
以下解决了这个问题,但这是一个暴行:我正在拉整个集合只是为了计算它,而我正在做我的排序客户端。我怎样才能让SQLAlchemy在数据库端做到这一点?
import operator
vars = {}
for v in db.session.query(Variable).all():
vars[v.id] = len(v.children)
sorted_vars = sorted(vars.items(), key=operator.itemgetter(1))
答案 0 :(得分:1)
获取直接子项数量的一种方法是按parent_id
分组并计数,但正如您所知,您将丢失没有子项的叶节点。要解决此问题,您可以创建计数的子查询并与Variable
联接,将NULL值合并为0.另一方面,在这种情况下不需要子查询:
child = aliased(Variable)
session.query(Variable,
func.coalesce(func.count(child.id), 0).label('child_count')).\
outerjoin(child, Variable.children).\
group_by(Variable.id).\
order_by(literal_column('child_count')).\
all()
由于主键保证不为NULL,因此只有左侧没有匹配权限或没有子节点,计数才会产生NULL值。如果您对实际计数不感兴趣,请在ORDER BY子句中完全移动它。