1

質問を 3 層のレベルで整理する必要があるクライアント向けのアンケートを作成しています。UI を正常に作成しましたが、過去 3 時間、すべてが適切な場所に読み込まれるようにデータベースからデータを取得しようとしました。データベースはクライアントによってそのように編成されているため、私はそれを制御できません:

id    description    parentId    about
1      Level 1        0           This is the top level or in my case tab1
2      Level 2        0           This is the next tab in the top level
3      Level 1a       1           This is the first category under tab1
4      Level 1b       1           This is the next category under tab1
5      Level 1a1      3           This is the content under the first category of tab1

したがって、parentId が 0 のものが最上位レベルであり、parentId が 1 の第 2 レベルのものが含まれます。はい、紛らわしいです、私はこれをほとんど理解できませんが、これは私がそうするように言われた方法です.

このようなことを実行するには、どのようなアプローチが最善の方法でしょうか? 私が参照として使用している別の質問の例を以下に添付します(ただし、機能しません)

foreach (mysql_query("SELECT * FROM pB_test ORDER BY id ASC") as $row) {
  $menuitem = array_merge(array(), $row);
  $menuLookup[$menuitem['id']] = $menuitem;
  if ($menuitem['parent'] == null) {
    $menuitem['path'] = "/" . $menuitem['name'];
    $menu[] = $menuitem[];
  } else {
    $parent = $menuLookup[$menuitem['parent']];
    $menuitem['path'] = $parent['path'] . "/" . $menuitem['name'];
    $parent['menu'][] = $menuitem;
  }
}

どんな助けでも大歓迎です。乾杯

4

3 に答える 3

1

ちょうど 3 つのレベルがある場合は、次のことを試すことができます。

http://sqlfiddle.com/#!2/70e96/16

(
  SELECT 1 AS lvl,
         top_level.description AS o1, top_level.id AS id1,
                          NULL AS o2,         NULL AS id2,
                          NULL AS o3,         NULL AS id3,
         top_level.*
  FROM   node AS top_level
  WHERE  top_level.parentId = 0
)UNION ALL(
  SELECT 2 AS lvl,
         top_level.description      AS o1, top_level.id      AS id1,
         category_level.description AS o2, category_level.id AS id2,
                               NULL AS o3,              NULL AS id3,
         category_level.*
  FROM       node AS top_level
  INNER JOIN node AS category_level ON category_level.parentId = top_level.id
  WHERE      top_level.parentId = 0
)UNION ALL(
  SELECT 3 AS lvl,
         top_level.description      AS o1, top_level.id      AS id1,
         category_level.description AS o2, category_level.id AS id2,
         last_level.description     AS o3, last_level.id     AS id3,
         last_level.*
  FROM       node AS top_level
  INNER JOIN node AS category_level ON category_level.parentId = top_level.id
  INNER JOIN node AS last_level ON last_level.parentId = category_level.id
  WHERE      top_level.parentId = 0
)
ORDER BY o1,o2,o3;

lvlレベルごとに異なる値のフィールドを選択に追加しました。また、ネストされたレベルをうまく並べるために o1、o2、o3 を追加しました。もちろん、別のニーズがあるかもしれません。PHP ですべての行を処理できます。たとえば、それらを 3 つの配列 (レベルごとに 1 つ) に分割したり、ID でルックアップ テーブルを作成したりできます。

于 2012-06-12T08:35:56.960 に答える
0

It might be worth doing this in PHP, as opposed to SQL if you're working with an external database. I haven't benchmarked the following, so try with your data and see if performance is problematic or not.

You can choose yourself what to do with orphaned records (which reference parentIDs that don't exist anymore).

Ordering in PHP like this requires that you have all of your data beforehand, so use something like PDO's fetchAll(PDO::FETCH_ASSOC) method, which should result in something like this:

$data_from_database = array(
    array("id" => 1, "parentId" => 0, "description" => "Level 1"),
    array("id" => 2, "parentId" => 1, "description" => "Level 1a"),
    array("id" => 3, "parentId" => 1, "description" => "Level 1b"),
    array("id" => 4, "parentId" => 0, "description" => "Level 2"),
    array("id" => 5, "parentId" => 2, "description" => "Level 1a1"),
    array("id" => 6, "parentId" => 5, "description" => "Level 1a11a"),
    array("id" => 7, "parentId" => 5, "description" => "Level 1a11b"),
    array("id" => 8, "parentId" => 9, "description" => "Level 3"),
);

First off, you'll want to have the primary key (ID) as the array's keys. The following also adds the keys "children" and "is_orphan" to every record.

$data_by_id = array();
foreach($data_from_database as $row)
    $data_by_id[$row["id"]] = $row + array(
        "children" => array(), 
        "is_orphan" => false
    );

This will look something like this:

$data_from_database = array(
    1 => array("id" => 1, "parentId" => 0, "description" => "Level 1", 
               "children" => array(), "is_orphan" => false),
    ...
 );

Now, it gets tricky: we'll loop through the array and add references.

foreach($data_by_id as &$row)
{
    if($row["parentId"] > 0)
    {
        if(isset($data_by_id[$row["parentId"]]))
            $data_by_id[$row["parentId"]]["children"][] = &$row;
        else
            $row["is_orphan"] = true;
    }
}
unset($row); // Clear reference (important).

The last step is to clean up the 'root' of the array. It'll contain references to duplicate rows.

foreach($data_by_id as $id => $row)
{
    // If you use this option, you'll remove
    // orphaned records.
    #if($row["parentId"] > 0)
    #    unset($data_by_id[$id]);

    // Use this to keep orphans:
    if($row["parentId"] > 0 AND !$row["is_orphan"])
        unset($data_by_id[$id]);
}

Use print_r($data_by_id) after every step to see what happens.

If this proves to be a time consuming operation, try to build up the tree by only doing SELECT id, parentId FROM ... and then later fetching the metadata such as description. You could also store the result in Memcache or serialized into a database.

于 2012-12-11T12:21:41.490 に答える
0

私も同じ種類の問題を抱えていましたが、多くのグーグルとスタックオーバーフローの後:-)私は自分の答えを見つけました....これが私のコーディング方法です。

function showComments($parent = 0)
{
$commentQuery = "SELECT * FROM comment WHERE parent = ".mysql_real_escape_string($parentId);
$commentResult = mysql_query($commentQuery)

while ($row = mysql_fetch_array($commentResult))
{
echo '[Table containing comment data]';
showComments($row['commentID']);
}
}

showComments();
于 2012-12-11T11:06:47.203 に答える