Linked list recursive query #11490
-
Hi!
I am trying to recursively get all rows that are connected. I can do it in sql, but can't figure out how I can do it in sqlalchemy.
Do you have any suggestions how to build such a query in sqlalchemy and what is the most efficient way? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Perhaps this simplified example might give you an idea on how to proceed: from pprint import pprint
from typing import Optional
from sqlalchemy import create_engine, ForeignKey, insert, select, literal_column
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Person(Base):
__tablename__ = "person"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=False)
name: Mapped[str]
parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("person.id"))
engine = create_engine("postgresql://scott:tiger@192.168.0.199/test")
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
person_table = Person.__table__
# populate example data
with engine.begin() as conn:
conn.execute(
insert(person_table),
[
dict(id=1, name='Abe "Grampa" Simpson', parent_id=None),
dict(id=2, name="Homer Simpson", parent_id=1),
dict(id=3, name="Bart Simpson", parent_id=2),
],
)
my_cte = (
select(
person_table.c.id,
person_table.c.name,
person_table.c.parent_id,
literal_column("0").label("depth"),
)
.where(person_table.c.parent_id.is_(None))
.cte(name="my_cte", recursive=True)
)
my_cte_alias = my_cte.alias(name="my_cte_alias")
my_cte = my_cte.union_all(
select(
person_table.c.id,
person_table.c.name,
person_table.c.parent_id,
(my_cte_alias.c.depth + 1).label("depth"),
).join(my_cte_alias, person_table.c.parent_id == my_cte_alias.c.id)
)
stmt = select(my_cte.c.name, my_cte.c.depth).order_by(my_cte.c.depth)
with Session(engine) as sess:
rows = sess.execute(stmt).mappings().all()
pprint(rows, width=20)
"""
[{'name': 'Abe "Grampa" Simpson', 'depth': 0},
{'name': 'Homer Simpson', 'depth': 1},
{'name': 'Bart Simpson', 'depth': 2}]
""" |
Beta Was this translation helpful? Give feedback.
Perhaps this simplified example might give you an idea on how to proceed: