如何在sqlite数据库中获取树并将节点转换为从它到根的路径?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在sqlite数据库中获取树并将节点转换为从它到根的路径?相关的知识,希望对你有一定的参考价值。

我有一个SQLite数据库,其中包含一个表示树的表。表中的每一行表示除了链接到自身的第一个节点之外的两个节点之间的关系。

基本上给出了这张表

BEGIN TRANSACTION;
CREATE TABLE "unnamed" (key TEXT PRIMARY KEY, value TEXT);
INSERT INTO `unnamed` (key,value) VALUES ('1','1');
INSERT INTO `unnamed` (key,value) VALUES ('2','1');
INSERT INTO `unnamed` (key,value) VALUES ('3','10');
INSERT INTO `unnamed` (key,value) VALUES ('10','5');
INSERT INTO `unnamed` (key,value) VALUES ('5','16');
INSERT INTO `unnamed` (key,value) VALUES ('16','8');
INSERT INTO `unnamed` (key,value) VALUES ('8','4');
INSERT INTO `unnamed` (key,value) VALUES ('4','2');
INSERT INTO `unnamed` (key,value) VALUES ('6','3');
INSERT INTO `unnamed` (key,value) VALUES ('7','22');
INSERT INTO `unnamed` (key,value) VALUES ('22','11');
INSERT INTO `unnamed` (key,value) VALUES ('11','34');
INSERT INTO `unnamed` (key,value) VALUES ('34','17');
INSERT INTO `unnamed` (key,value) VALUES ('17','52');
INSERT INTO `unnamed` (key,value) VALUES ('52','26');
INSERT INTO `unnamed` (key,value) VALUES ('26','13');
INSERT INTO `unnamed` (key,value) VALUES ('13','40');
INSERT INTO `unnamed` (key,value) VALUES ('40','20');
INSERT INTO `unnamed` (key,value) VALUES ('20','10');
INSERT INTO `unnamed` (key,value) VALUES ('9','28');
INSERT INTO `unnamed` (key,value) VALUES ('28','14');
INSERT INTO `unnamed` (key,value) VALUES ('14','7');
COMMIT;

输出此表

+------+------------------------------------------------------+
| Node | Path                                                 |
+------+------------------------------------------------------+
|    1 | 1                                                    |
|    2 | 2-1                                                  |
|    3 | 3-10-5-16-8-4-2-1                                    |
|    4 | 4-2-1                                                |
|    5 | 5-16-8-4-2-1                                         |
|    6 | 6-3-10-5-16-8-4-2-1                                  |
|    7 | 7-22-11-34-17-52-26-13-40-20-10-5-16-8-4-2-1         |
|    8 | 8-4-2-1                                              |
|    9 | 9-28-14-7-22-11-34-17-52-26-13-40-20-10-5-16-8-4-2-1 |
|   10 | 10-5-16-8-4-2-1                                      |
|   11 | 11-34-17-52-26-13-40-20-10-5-16-8-4-2-1              |
|   13 | 13-40-20-10-5-16-8-4-2-1                             |
|   14 | 14-7-22-11-34-17-52-26-13-40-20-10-5-16-8-4-2-1      |
|   16 | 16-8-4-2-1                                           |
|   17 | 17-52-26-13-40-20-10-5-16-8-4-2-1                    |
|   20 | 20-10-5-16-8-4-2-1                                   |
...

我一直在阅读有关WITHWITH RECURSIVE的文章,但我无法理解他们的工作方式。

答案

此解决方案构建从leaf到root的路径:

WITH RECURSIVE
  queue(leaf,head,path) AS (
    SELECT CAST(key AS INTEGER) AS leaf, key AS head, key AS path
      FROM unnamed
    UNION
    SELECT queue.leaf AS leaf, unnamed.value AS head, (queue.path||'-'||unnamed.value) AS path
      FROM unnamed, queue
      WHERE unnamed.value != queue.head AND unnamed.key = queue.head
  )
SELECT leaf AS node, path AS path
  FROM queue
  WHERE head = 1
  -- WHERE length(path) = (SELECT MAX(LENGTH(path)) FROM queue AS q WHERE q.leaf = queue.leaf)
  ORDER BY leaf;

请阅读此处的文档:http://www.sqlite.org/lang_with.html

initial-select将所有键作为叶子和头部和路径添加到队列中。对于ORDER BY,Leaf将被转换为整数,head是当前头,并且路径将逐步扩展:

SELECT CAST(key AS INTEGER) AS leaf, key AS head, key AS path
    FROM unnamed

对于每个队列项,将查询数据库以将头部的路径扩展到树的根。因此队列项的头部必须匹配一个键,该键不是树的根。

WHERE unnamed.value != queue.head AND unnamed.key = queue.head

两者的组合路径用短划线扩展并添加到队列中:

SELECT queue.leaf AS leaf, unnamed.value AS head, (queue.path||'-'||unnamed.value) AS path
    FROM unnamed, queue
    WHERE unnamed.value != queue.head AND unnamed.key = queue.head

结果包含从leaf到root的所有路径,包括所有中间结果。因此,我们只选择那些以头/键值1结束于根节点的那些。

SELECT leaf AS node, path AS path
    FROM queue
    WHERE head = 1
    ORDER BY leaf;

或者,您也可以选择路径最长的那些。

SELECT leaf AS node, path AS path
    FROM queue
    WHERE length(path) = (SELECT MAX(LENGTH(path)) FROM queue AS q WHERE q.leaf = queue.leaf)
    ORDER BY leaf;

以上是关于如何在sqlite数据库中获取树并将节点转换为从它到根的路径?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 expo react native 中使用 sqlite 文件

在tkinter的treeview中的for循环中的每个父节点下添加子节点

Android:如何用相机拍照并将位图转换为字节数组并保存到sqlite db?

如何将表达式树转换为部分 SQL 查询?

我可以从它的内存地址中获取一个 python 对象吗?

如何将 Python 十进制转换为 SQLite 数字?