7

私のテーブル データは、1 つの行が同じテーブルの親行を参照できるツリー構造を形成します。

私が Slick を使用して達成しようとしているのは、行とそのすべての子を返すクエリを作成することです。また、同じことをしたいのですが、子とそのすべての先祖を返すクエリを書きます。

言い換えると:

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 }

しかし、Slick が id と id_parent リンクを使用して同じテーブルを再帰的に検索する方法を探しています。問題を解決する他の良い方法は大歓迎です。ただし、データベースの往復回数を最小限に抑えることが最善であることを覚えておいてください。

4

2 に答える 2

1

slick から 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
于 2013-03-15T23:05:01.933 に答える
-1

プレーンな SQL では、これはトリッキーです。複数のオプションがあります。

  1. ストアド プロシージャを使用して、正しいレコードを (再帰的に) 収集します。次に、コードを使用してそれらのレコードをツリーに変換します
  2. すべてのレコードを選択し、コードを使用してそれらをツリーに変換します
  3. ここ(ツリー構造用に最適化された SQLから) およびここで説明されているように、より高度な手法を使用します。次に、コードを使用してそれらのレコードをツリーに変換します

SQL で実行する方法に応じて、Slick クエリを作成する必要があります。Leaky Abstractionsの概念は、ここで非常に明白です。

したがって、ツリー構造を取得するには、次の 2 つの手順が必要です。

  1. 正しい (またはすべての) レコードを取得する
  2. それらのレコードから (通常のコードを使用して) ツリーを構築する

Slick を使用しているので、それはオプションではないと思いますが、別のデータベース タイプの方がデータ モデルにより適している可能性があります。さまざまなタイプの違いについては、NoSQLを確認してください。

于 2013-02-25T16:29:00.443 に答える