我需要多少SQL查询?

我需要多少SQL查询?,sql,database,sqlite,Sql,Database,Sqlite,我有一个数据库表(sqlite),其中包含形成树层次结构的项。每个项目都有一个id字段(对于自身)和一个父项id。现在给定一个项,我必须检索从根到项的整个链 伪代码中的算法基本上如下所示: 光标是一个项目 按parentId检索游标的parentItem 如果parentItem不是rootItem,则cursor=parentItem并转到2 因此,我必须对每个项目执行一个SQL SELECT查询 是否可以检索整个链rootItem->…->通过只执行一个SQL查询来创建项目?不使用ANSI标

我有一个数据库表(sqlite),其中包含形成树层次结构的项。每个项目都有一个id字段(对于自身)和一个父项id。现在给定一个项,我必须检索从根到项的整个链

伪代码中的算法基本上如下所示:

  • 光标是一个项目
  • 按parentId检索游标的parentItem
  • 如果parentItem不是rootItem,则cursor=parentItem并转到2
  • 因此,我必须对每个项目执行一个SQL SELECT查询


    是否可以检索整个链rootItem->…->通过只执行一个SQL查询来创建项目?

    不使用ANSI标准SQL,它不是,不。严格来说,这不是真的。您可以进行左侧外部连接,并输入足够的内容以覆盖可能的最大深度,但除非您限制最大深度并包含那么多连接,否则它将无法始终工作

    如果您的行集足够小(比如少于1000行),只需检索所有行,然后计算出来。它很可能比单次读取遍历更快

    您可以批处理父遍历。有如下查询:

    SELECT t1.id id1, t1.parent parent1,
           t2.id id2, t2.parent parent2,
           t3.id id3, t3.parent parent3,
           t4.id id4, t4.parent parent4,
           t5.id id5, t5.parent parent5
    FROM mytable t1
    LEFT OUTER JOIN mytable t2 ON t1.parent = t2.id
    LEFT OUTER JOIN mytable t3 ON t2.parent = t3.id
    LEFT OUTER JOIN mytable t4 ON t3.parent = t4.id
    LEFT OUTER JOIN mytable t5 ON t4.parent = t5.id
    WHERE t1.id = 1234
    
    把它扩展到你想要的任何数字。如果最后检索到的父项不为null,那么您还不在树的顶部,因此再次运行查询。这样,您应该希望将其减少到1-2次往返

    除此之外,您可以查看在ID中对该数据进行编码的方法。不建议这样做,但如果您将每个节点限制为100个子节点,则可以说ID为10030711的节点的路径为10->03->07->11。这当然还有其他问题(比如最大ID长度),当然也有问题


    值得注意的是,SQL中的分层数据有两个基本模型。邻接列表和嵌套集。您的方式(非常常见)是邻接集。嵌套集在这种情况下并没有真正的帮助,而且它们很难进行插入。

    在数据库中组织层次结构数据有很多创造性的方法,但我始终发现以非层次结构格式返回数据,然后以编程方式匹配父记录和子记录是最容易的

    总工作量:1次查询+1次通过数据集编程来创建层次结构


    备选办法:

    我过去使用过这种方法,但效果有限。您可以使用varchar(max)列存储树中每个项目的路径,如下所示:

    ID    ParentID    Path
    --    --------    ----
    1     null        1/
    2     1           1/2/
    3     null        3/
    4     2           1/2/4/
    5     4           1/2/4/5/
    6     null        6/
    7     5           1/2/4/5/7/
    9     5           1/2/4/5/9/
    
    从这一点来看,获取ID=5下的所有节点是一个非常简单的过程:

    SELECT *
    FROM table
    WHERE Path like (SELECT Path FROM Table WHERE ID = 5) + '%'
    

    您可以更改表结构吗?看起来存储左侧和右侧节点比只存储父节点更容易,因为这样就可以进行单个选择。请参阅以下链接:


    (这是SQLServer,但他们有一个图表可能会有所帮助。)

    不幸的是,我的行集相当大,甚至在不断增长。技术不错,我想+1,但我有几个小时没有投票了。为什么说“有限成功”呢?为什么不直接从路径为“%/5/%”的表中选择*@eyze:当然,这也可以:)但是,在几乎所有的数据库实现中,数据库不能对以通配符开头的类似表达式使用索引。请参阅SQLite文档():“由LIKE或GLOB运算符组成的术语有时可用于约束索引。在这种使用上有许多条件:[……]LIKE或GLOB的右侧必须是不以通配符开头的字符串文字”。我不确定上面的代码是否会使用索引,因为它不是字符串文字。YMMV。@eyze:也许“有限的成功”不是最好的措辞。我曾在小型个人项目中使用过这种技术,但从未在大型表或深层层次上真正尝试过。不过,仍然值得再做一些尝试:)