Мне трудно оптимизировать мои запросы SQLAlchemy. Мои знания SQL очень базовые, и я просто не могу получить то, что мне нужно, из документации SQLAlchemy.
Предположим следующее очень простое отношение «один ко многим»:
class Parent(Base):
__tablename__ = "parents"
id = Column(Integer, primary_key = True)
children = relationship("Child", backref = "parent")
class Child(Base):
__tablename__ = "children"
id = Column(Integer, primary_key = True)
parent_id = Column(Integer, ForeignKey("parents.id"))
naughty = Column(Boolean)
Как я мог:
- Запросить кортежи
(Parent, count_of_naughty_children, count_of_all_children)
для каждого родителя?
После приличного времени, потраченного на гугление, я нашел, как запрашивать эти значения по отдельности:
# The following returns tuples of (Parent, count_of_all_children):
session.query(Parent, func.count(Child.id)).outerjoin(Child, Parent.children).\
group_by(Parent.id)
# The following returns tuples of (Parent, count_of_naughty_children):
al = aliased(Children, session.query(Children).filter_by(naughty = True).\
subquery())
session.query(Parent, func.count(al.id)).outerjoin(al, Parent.children).\
group_by(Parent.id)
Пробовал комбинировать их по-разному, но не получилось получить то, что я хочу.
- Опросите всех родителей, у которых более 80% непослушных детей? Изменить: непослушный может быть NULL.
Я предполагаю, что этот запрос будет основан на предыдущем, фильтруя по соотношению непослушные/все.
Любая помощь приветствуется.
EDIT: Благодаря помощи Антти Хаапала я нашел решение второго вопроса:
avg = func.avg(func.coalesce(Child.naughty, 0)) # coalesce() treats NULLs as 0
# avg = func.avg(Child.naughty) - if you want to ignore NULLs
session.query(Parent).join(Child, Parent.children).group_by(Parent).\
having(avg > 0.8)
Он находит среднее значение для дочерней переменной naughty
, рассматривая False и NULL как 0, а True как 1. Протестировано с серверной частью MySQL, но должно работать и с другими.