用油滑递归树状表查询(Recursive tree-like table query with Sl

2019-08-17 03:57发布

我的表中的数据形成一个树型结构,其中一列可以在同一个表中引用父行。

我想实现,使用油滑的,是写一个查询,将返回一行和所有它的孩子。 另外,我想这样做,但编写一个查询将返回一个孩子和所有它的祖先。

换一种说法:

findDown(1)应返回

List(Group(1, 0, "1"), Group(3, 1, "3 (Child of 1)"))

findUp(5)应返回

List(Group(5, 2, "5 (Child of 2)"), Group(2, 0, "2"))

这里是一个全功能的工作表(除了丢失的解决方案;-)。

package com.exp.worksheets

import scala.slick.driver.H2Driver.simple._

object ParentChildTreeLookup {

  implicit val session = Database.forURL("jdbc:h2:mem:test1;", driver = "org.h2.Driver").createSession()

  session.withTransaction {
    Groups.ddl.create
  }

  Groups.insertAll(
    Group(1, 0, "1"),
    Group(2, 0, "2"),
    Group(3, 1, "3 (Child of 1)"),
    Group(4, 3, "4 (Child of 3)"),
    Group(5, 2, "5 (Child of 2)"),
    Group(6, 2, "6 (Child of 2)"))

  case class Group(
    id: Long = -1,
    id_parent: Long = -1,
    label: String = "")

  object Groups extends Table[Group]("GROUPS") {
    def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
    def id_parent = column[Long]("ID_PARENT")
    def label = column[String]("LABEL")
    def * = id ~ id_parent ~ label <> (Group, Group.unapply _)
    def autoInc = id_parent ~ label returning id into {
      case ((_, _), id) => id
    }

    def findDown(groupId: Long)(implicit session: Session) = { ??? }

    def findUp(groupId: Long)(implicit session: Session) = { ??? }
  }

}

在一个非常糟糕的,和静态尝试findDown可能是这样的:

private def groupsById = for {
  group_id <- Parameters[Long]
  g <- Groups; if g.id === group_id
} yield g

private def childrenByParentId = for {
  parent_id <- Parameters[Long]
  g <- Groups; if g.id_parent === parent_id
} yield g


def findDown(groupId: Long)(implicit session: Session) = { groupsById(groupId).list union childrenByParentId(groupId).list }

但是,我正在寻找一个圆滑的方式来递归搜索使用id和id_parent链接同桌。 任何其他好的方法来解决这个问题实在是值得欢迎的。 但请记住,这将是最好的,以尽量减少数据库往返次数。

Answer 1:

你可以尝试从光滑调用SQL。 SQL调用上去层次会是这个样子(这是SQL Server):

WITH org_name AS 
(
    SELECT DISTINCT
        parent.id AS parent_id,
        parentname.label as parent_label,
        child.id AS child_id,
        childname.ConceptName as child_label
    FROM
        Group parent RIGHT OUTER JOIN 
        Group child ON child.parent_id = parent.id
), 
jn AS 
(   
    SELECT
        parent_id,
        parent_label,
        child_id,
        child_label
    FROM
        org_name 
    WHERE
        parent_id = 5
    UNION ALL 
        SELECT
            C.parent_id,
            C.parent_label,
            C.child_id,
            C.child_label 
        FROM
            jn AS p JOIN 
            org_name AS C ON C.child_id = p.parent_id
) 
SELECT DISTINCT
    jn.parent_id,
    jn.parent_label,
    jn.child_id,
    jn.child_label
FROM
    jn 
ORDER BY
    1;

如果你想下去层次改变行:

org_name AS C ON C.child_id = p.parent_id

org_name AS C ON C.parent_id = p.child_id


Answer 2:

在普通的SQL,这将是棘手的。 您将有多种选择:

  1. 使用存储过程来收集正确的记录(递归)。 然后转换这些记录成一棵树使用代码
  2. 选择的所有记录,这些转换成树使用代码
  3. 使用所描述的更先进的技术, 在这里 (从优化SQL为树形结构 ),并在这里 。 然后转换这些记录成一棵树使用代码

根据你想这样做在SQL的方式,你需要建立一个灵活的查询。 概念漏抽象是非常明显的在这里。

因此让树结构需要两个步骤:

  1. 得到正确的(或所有记录)
  2. 建立(使用常规代码)一棵树从这些记录

由于您使用的油滑,我不认为这是一种选择,但另一个数据库类型可能是你的数据模型更适合。 检查出的NoSQL的不同类型之间的差异。



文章来源: Recursive tree-like table query with Slick
标签: scala slick