簡體   English   中英

按 SQLAlchemy 中自引用子集合的長度對對象進行排序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM