SQLAlchemy基本递归CTE示例分层树查询

2024-05-16 23:42:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难理解如何在SQLAlchemy中实现递归cte。不是没有例子,就是我不懂,就是找不到。在

实际上,我在python3.7中使用django2.2,在MySQL 8中使用Conda和SQLAlchemy。但据我所知,这对我的问题并不重要。在

我根据this指南在MySQL中创建了一个相邻列表模型,并查看了SQLAlchemy的this手册。 问题在MWE之后。在

我的数据库定义是:

CREATE TABLE events (
 id int(10) UNSIGNED AUTO_INCREMENT,
 name varchar(255) ,
 parent_id int(10) UNSIGNED DEFAULT NULL,
 description varchar(255) DEFAULT=NULL,
 PRIMARY KEY (id),
 FOREIGN KEY (parent_id) REFERENCES events (id)
);

使用这些虚拟条目:

^{pr2}$

在Django中,我创建了这个模型定义以使用SQLAlchemy进行访问

class Events(Base):
    __tablename__ = 'events'
    id = Column(INTEGER(10), primary_key=True)
    parent_id = Column(INTEGER(10), ForeignKey('events.id'))
    name = Column(String(255))
    description = Column(String(255))

    children = relationship('Events')

到目前为止,SQLAlchemy中的简单querys就像一个符咒。但是我不明白如何将WITH RECURSIVE和类似的请求转换成SQLAlchemy查询。在

例如,要求5列(最后2列是通过递归更改/创建的),显示每个数据库项的树和深度:

WITH RECURSIVE hierarchy AS
(
  SELECT id, name, parent_id, 1 AS depth, name AS path
    FROM events
    WHERE parent_id IS NULL
  UNION ALL
  SELECT e.id, e.name, e.parent_id, h.depth + 1, CONCAT(h.path, ' > ', e.name)
    FROM hierarchy AS h 
      JOIN events AS e ON h.id = e.parent_id
)
SELECT * FROM hierarchy;

我找到了this查询示例,并尝试按如下方式修改它(其中as parent应该表示上面的path):

hierarchy = self.session.query(
        Events, literal(0).label('level'), null().label('parent')
    ).filter(
        Events.parent_id == null()
    ).cte(name='hierarchy',recursive=True)

h = aliased(hierarchy, 'h')
e = aliased(Events, 'e')

hierarchy = hierarchy.union(
    self.session.query(
        e2, (h.c.level + 1).label('level'), h.c.name                         
    ).filter(
        (e2.parent_id == h.c.id)
    )
)
result = self.session.query(Events, hierarchy.c.level).all()

上面代码的最后一行发出一个错误,声明(1406, "Data too long for column 'parent' at row 1")以及创建的SQL语句:

WITH RECURSIVE hierarchy(id, parent_id, name, description, level, parent) AS (
 SELECT events.id AS id, events.parent_id AS parent_id, events.name AS name, events.description AS description, %(param_1)s AS level, %(param_2)s AS parent 
 FROM events 
 WHERE events.parent_id IS NULL 
 UNION 
 SELECT e2.id AS e2_id, e2.parent_id AS e2_parent_id, e2.name AS e2_name, e2.description AS e2_description, anon_1.level + %(level_1)s AS level, anon_1.name AS anon_1_name 
 FROM events AS e2, hierarchy AS anon_1 
 WHERE e2.parent_id = anon_1.id
)
SELECT events.id AS events_id, events.parent_id AS events_parent_id, events.name AS events_name, events.description AS events_description, hierarchy.level AS hierarchy_level 
FROM events, hierarchy;

问题

  1. 有没有人可以提供一个有详细解释的链接 关于如何在SQLAlchemy中转换为递归CTE查询?在
  2. 在SQLAlchemy查询中,.cte(recursiv=True)到底是什么?name=hierarchy可能正在设置一个特定的名称,否则该名称将是虚构的。

  3. 为什么会出现错误Data too long...,我该如何解决这个问题(这个问题中的实际输出并不重要,而是要弄清楚到底什么东西太长了,它是从哪里来的)?

  4. 为什么有必要引用c作为h的字段,例如h.c.name\h.c.level,它来自哪里?

  5. (如何在此查询中使用func.concat来显示与CONCAT(h.path, ' > ', e.name)相似的路径?)

我可以看出这是一个有点不寻常的问题,我可能是从一个错误的角度来看待它,但我花了相当长的时间来理解这个话题,而且还没有走得很远。在

如有任何关于如何改进我的问题的帮助或建议,我们将不胜感激。在


Tags: namefromidhierarchysqlalchemyasdescriptionevents