【问题标题】:query parents in a tree在树中查询父母
【发布时间】:2017-10-08 07:10:04
【问题描述】:

我有如下数据库表任务。

SELECT _id,name,parentId FROM Task;

_id         name                  parentId  
----------  --------------------  ----------
4           Software Development            
5           Machine Learning                
6           Programing            4         
7           Build System          4         
8           version control       4         
9           Android App Developm  4         
10          Udacity Cource        5         
11          Mathematics           5         
12          skLearn docs          5         
13          problem solving       6         
14          breakdown             13        
15          language              6         
16          c                     15        
17          c++                   15        
18          java                  15        
19          kotlin                15        
20          gradle                7         
21          bazel                 7         
22          git                   8         
23          svn                   8         

所有任务及其子任务都在一个表中,使用_id(主键)和parentId与各自的父任务相关。

例如任务名称 'java' 有 _id = 18 和 parentId = 15 意味着 'java' 是 _id = 15 的子任务,即 'language'。

同样,“语言”的 _id = 15 和 parentId = 6 意味着“语言”是 _id = 6 的子任务,即“编程”。

同样的“编程”是“软件开发”的子任务。

而“软件开发”是 null 的子任务。

所以我需要一个查询,它为输入_id = 18(即'java')提供如下输出,它是父任务列表,父任务的父...任务。

_id 名称 parentId 4 软件开发 null 6 编程 4 15 语言 6 18 爪哇 15

目前我可以在一个循环中使用 4 个查询来获取此输出。

SELECT _id,name,parentId FROM task WHERE _id = 18

在下一次迭代中,_id 将是上述查询输出中 parentId 的值

这很耗时,所以我们可以为此提供更好的解决方案。

【问题讨论】:

标签: android sqlite android-sqlite recursive-cte


【解决方案1】:

要上树需要递归common table expression

WITH RECURSIVE parents(id, name, parentid, level) AS (
  SELECT _id, name, parentid, 1
  FROM Task
  WHERE _id = 18

  UNION ALL

  SELECT Task._id, Task.name, Task.parentid, level + 1
  FROM Task
  JOIN parents ON Task._id = parents.parentid
)
SELECT id, name, parentid
FROM parents
ORDER BY level DESC;

在 Android Lollipop(API 级别 21)之前不支持此功能。

【讨论】:

  • 感谢您的回答!我得到上述查询的输出是 18 |爪哇 | 15 而不是所需的输出。你的方法看起来很写,但仍然缺少一些东西!
  • 'WITH' 来自 sqlite 3.8.3 或更高版本的支持
【解决方案2】:

我也有这样的业务,我结合sql和java代码来解决这个问题。 就是这样:

    public ArrayList<String> getRecursiveReverse(String parentId) throws Exception {
    StringBuffer  sqlObject = new StringBuffer();
    sqlObject.append("SELECT T.TABLE_ID ");
    sqlObject.append("FROM   TABLE_NAME T ");
    sqlObject.append("WHERE  1 = 1 ");
    sqlObject.append("       AND T.STATUS = 1 ");
    sqlObject.append("       AND T.PARENT_ID = ? ");

    Cursor c = null;
    String[] params = { parentId };
    ArrayList<String> listIdArray = new ArrayList<String>();
    if (!StringUtil.isNullOrEmpty(parentId)) { 
            listIdArray.add(parentId);
    }
    try {
        c = rawQuery(sqlObject.toString(), params);
        if (c != null) {
            if (c.moveToFirst()) {
                do {
                    String tableId = CursorUtil.getString(c, "TABLE_ID");

                    ArrayList<String> tempArray = getShopRecursiveReverse(tableId);
                    listIdArray.addAll(tempArray);
                } while (c.moveToNext());
            }
        }
    } finally {
        try {
            if (c != null) {
                c.close();
            }
        } catch (Exception e) {
            MyLog.w(getTAG(), GlobalUtil.getCurrentMethodName(), e);
        }
    }
    return listIdArray;
}

【讨论】:

  • 并且从 sqlite 版本 3.8.3 开始支持 WITH 子句。也许您可以使用 with 'WITH 子句'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
相关资源
最近更新 更多