簡體   English   中英

使用遞歸PHP組織MySQL數據

[英]Organizing mySQL data using recursive PHP

我正在為客戶創建一個問卷,該問卷要求問題按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的第二個級別的內容,依此類推。 令人困惑的是,我幾乎無法理解這一點,但這就是我被告知要這樣做的方式。

什么方法是執行這樣的最佳方法? 下面附有我正在用作參考的另一個問題的示例(盡管不起作用)

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;
  }
}

任何幫助將不勝感激。 干杯

如果您正好有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個數組(每個級別一個),或者按ID創建查找表,等等。

我也有同樣的問題,但是經過大量的搜索和堆棧溢出:-)我找到了答案。...這是我的編碼方式。

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();

如果要使用外部數據庫,則可能需要用PHP而不是SQL來做到這一點。 我尚未對以下各項進行基准測試,因此請嘗試使用您的數據,看看性能是否有問題。

您可以選擇自己處理孤立記錄(該記錄引用不再存在的parentID)。

以這種方式在PHP中進行排序要求您事先擁有所有數據,因此請使用PDO的fetchAll(PDO::FETCH_ASSOC)方法之類的方法,這將導致如下所示的結果:

$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"),
);

首先,您需要將主鍵(ID)作為陣列的鍵。 以下還將鍵“ children”和“ is_orphan”添加到每個記錄。

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

看起來像這樣:

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

現在,它變得棘手:我們將遍歷數組並添加引用。

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).

最后一步是清理陣列的“根”。 它將包含對重復行的引用。

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]);
}

在每個步驟之后使用print_r($data_by_id)看看會發生什么。

如果證明這是一項耗時的操作,請嘗試僅通過執行SELECT id, parentId FROM ...來構建樹,然后再獲取諸如description的元數據。 您也可以將結果存儲在Memcache中或序列化到數據庫中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM