Не понимаю как работает запрос SQL (sqlalchemy, 2x outerjoin , count)
Приветствую сообщество ru.stackoverflow! Я задал 2 дня вопрос и получил на него корректный ответ. Задача была сделать запрос подсчета количества яблок для садовода, при том, что у садовода может быть несколько деревьев, а у каждого дерева может быть несколько яблок. Правильным быстрым(мой прежний код работал очень долго) ответом стало:
select g.gardener_id g.name, count(a.apple_id) apples_qty from gardeners g
LEFT JOIN trees t on t.gard_id = g.gardener_id
LEFT JOIN apples a on a.ap_tree_id = t.tree_id
GROUP BY g.gardener_id, g.name
Я разобрался с запросом и решил перенести это в sqlalchemy. Вот, что у меня получилось после очень долгих мучений:
def apples_count(name: str) -> int:
return (session.query(Gardener, sqlalchemy.func.count(AppleTrees.tree_id))
.outerjoin(AppleTrees)
.group_by(Gardener)
.outerjoin(Apples)
.group_by(Gardener)
.filter(Gardener.name == name)
).all()[0][1]
Код работает исправно, но я не понимаю, как это мы считаем количество деревьев count(AppleTrees.tree_id), а получаем корректное количество яблок(испр. неверное утверждение - не будет работать, если дерево пустое). При этом я пытался искать именно Gardener, sqlalchemy.func.count(Apple.apple_id) - но у меня вообще никак не получалось.
Вот такой код выдает sqlalchemy:
SELECT gardener.gardener_id AS gardener_gardener_id, gardener.name AS gardener_name, count(trees.tree_id) AS count_1 FROM gardener
LEFT OUTER JOIN trees ON gardener.gardener_id = trees.gard_id
LEFT OUTER JOIN aples ON trees.tree_id = aples.ap_tree_id
WHERE gardener.name = %(name_1)s
GROUP BY gardener.gardener_id
Напомню таблицы
class Gardener(Base):
__tablename__ = 'gardeners'
gardener_id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(15))
apple_trees = relationship('AppleTrees', backref='gardener_trees')
class AppleTrees(Base):
__tablename__ = 'trees'
tree_id = Column(Integer, primary_key=True, autoincrement=True)
gard_id = Column(Integer, ForeignKey('gardeners.gardener_id'))
apples = relationship('Apples', backref='tree_apples')
class Apples(Base):
__tablename__ = 'apples'
apple_id = Column(Integer, primary_key=True, autoincrement=True)
ap_tree_id = Column(Integer, ForeignKey('trees.tree_id'))