[英]Sort objects by length of self-referencing child collection in SQLAlchemy
我有一個表示層次結構的數據庫表,這意味着它有一個自引用外鍵。 我想按對象的孩子數量對它們進行排序。
問題是我既不知道如何進行適當的自聯接,也不知道如何在原始查詢中詢問子集合的計數。 結果是我不得不求助於檢索子項,獲取子項集合長度,並在 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))
獲取直接子節點數量的一種方法是僅按parent_id
和計數分組,但正如您所指出的,您會丟失沒有子節點的葉節點。 為了解決這個問題,您可以創建一個計數的子查詢,並重新連接到Variable
,將 NULL 值合並為 0。另一方面,在這種情況下,子查詢是不必要的:
child = aliased(Variable)
session.query(Variable,
func.count(child.id).label('child_count')).\
outerjoin(child, Variable.children).\
group_by(Variable.id).\
order_by(literal_column('child_count')).\
all()
由於主鍵保證不為 NULL,因此計數將僅為沒有匹配的右側或沒有子項的左側產生 NULL 值。 如果您對實際計數不感興趣,請將其完全移動到 ORDER BY 子句中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.