我希望使用MySQL和SQLAlchemy(0.7)在SQL表中有多个链表。所有列表的第一个节点都是父节点为0,子节点为0。id表示列表,而不是独立元素。该元素由PK 识别
有了一些省略的语法(与问题无关),它应该看起来像这样:
id(INT, PK)
content (TEXT)
parent(INT, FK(id), PK)
child(INT, FK(id), PK)
由于该表有多个链表,如何从数据库中返回整个列表?我选择了一个特定的ID,父项为0?
例如:
SELECT * FROM ... WHERE id = 3 AND parent = 0
假设在同一个表中存储了多个链表,我假设您将这些链表的HEAD和/或TAIL存储在其他一些表中。很少有想法:
1)保留链接列表:从数据查询的角度来看,第一个大的改进(也在评论中提出)是为同一列表中的所有节点提供一些公共标识符(让我们称之为ListID
)。这里有几个选项:
- 如果每个列表仅从一个对象(数据行)引用[我甚至会提出这样的问题:"列表是否属于单个对象?],那么这个
ListID
可以只是持有者对象的(主要)标识符,ForeignKey
在顶部,以确保数据完整性。在这种情况下,查询所有列表非常简单。事实上,您可以定义relationship
并像my_object.my_list_items
一样对其进行导航 - 如果列表由多个对象使用/引用,则可以创建另一个表,该表将仅由一列
ListID (PK)
组成,并且每个节点/项都将再次具有ForeignKey或类似的内容 - 否则,可以在两个查询/SQL语句中加载大列表:
- 按ID查询HEAD/TAIL
- 根据接收到的HEAD/TAIL的
ListID
查询整个列表
事实上,这可以用一个查询来完成,比如下面的查询(单查询示例),从IO的角度来看效率更高,但分两个步骤完成的好处是可以立即引用HEAD(或TAIL)节点
单个查询示例:
# single-query using join (not tested)
Head = alias(Node)
qry = session.query(Node).join(Head, Node.ListID == Head.ListID).filter(Head.ID == head_node_id)
在任何情况下,为了遍历链表,您都必须根据其ID获取HEAD/TAIL,然后像往常一样遍历
注意:在这里,我不确定SA是否会识别出引用对象已经加载到会话中,或者会为每个引用对象发出其他SQL语句,这将无法实现批量加载的目的
2)用Ordering List
扩展名替换链表:
请阅读订购单文档。Ordering List
的实现可能足够好,您可以使用它来代替链接列表