Pra*_*hed 5 python mysql recursion sqlalchemy common-table-expression
我无法理解如何在 SQLAlchemy 中实现递归 CTE 。要么没有例子,要么我不理解它们,要么找不到它们。
我实际上正在使用 Django 2.2 和 Python 3.7、Conda 和 SQLAlchemy 和 MySQL 8。但据我了解/已经注意到,这对我的问题并不重要。
我按照本指南在 MySQL 中创建了一个相邻列表模型,并查看了SQLAlchemy 的本手册。 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)
);
Run Code Online (Sandbox Code Playgroud)
并使用这个虚拟条目:
INSERT INTO events (id, name, parent_id) VALUES (1, "root", null);
INSERT INTO events (id, name, parent_id) VALUES (2, "A", 1);
INSERT INTO events (id, name, parent_id) VALUES (3, "B", 1);
INSERT INTO events (id, name, parent_id) VALUES (4, "C", 1);
INSERT INTO events (id, name, parent_id) VALUES (5, "D", 1);
INSERT INTO events (id, name, parent_id) VALUES (6, "A1", 2);
INSERT INTO events (id, name, parent_id) VALUES (7, "A2", 2);
INSERT INTO events (id, name, parent_id) VALUES (8, "B1", 3);
INSERT INTO events (id, name, parent_id) VALUES (9, "B2", 3);
INSERT INTO events (id, name, parent_id) VALUES (10, "D1", 5);
INSERT INTO events (id, name, parent_id) VALUES (11, "A1A", 6);
INSERT INTO events (id, name, parent_id) VALUES (12, "A1B", 6);
Run Code Online (Sandbox Code Playgroud)
在 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')
Run Code Online (Sandbox Code Playgroud)
到目前为止,SQLAlchemy 中的简单查询非常有效。但我无法理解如何将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;
Run Code Online (Sandbox Code Playgroud)
我找到了这个查询示例并尝试按如下方式对其进行调整(其中 asparent应该代表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()
Run Code Online (Sandbox Code Playgroud)
上面代码的最后一行发出错误说明(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;
Run Code Online (Sandbox Code Playgroud)
问题
.cte(recursiv=True)SQLAlchemy 查询中到底做了什么?name=hierarchy可能是设置一个特定的名称,否则该名称将是虚构的。
为什么会发出错误Data too long...,我该如何解决这个问题(这个问题的实际输出并不重要,而是要找出到底什么太长以及它来自哪里)?
为什么需要引用例如\c字段?它从何而来?hh.c.nameh.c.level
(如何func.concat在此查询中使用来显示类似于 的路径CONCAT(h.path, ' > ', e.name)?)
我可以看到这是一个有点不寻常的问题,我可能从错误的角度看待它,但我花了相当长的时间来理解这个主题,但还没有走得太远。
对于如何改进我的问题的任何帮助或建议,我们将不胜感激。
| 归档时间: |
|
| 查看次数: |
2385 次 |
| 最近记录: |