2012-06-12 79 views
1

我正在爲客戶創建一個問卷,要求通過3層關卡來組織問題。我已經成功創建了U.I.然而,我一直試圖在最後3個小時從數據庫中提取數據,以便將所有內容加載到正確的位置。該數據庫由客戶舉辦像這樣,所以我有沒有對其進行控制:使用遞歸組織mySQL數據PHP

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 

所以爲0的parentId的東西是頂級水平,將包含第二個層次的東西用的1等的parentId的上。令人困惑的是,我幾乎無法理解這一點,但這是我被告知要這樣做的方式。

什麼方法是執行這樣的事情的最好方法?我用作參考的另一個問題的示例附在下面(儘管不起作用)

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

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

回答

0

如果您使用外部數據庫,則可能需要在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中或序列化到數據庫中。

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個數組(每個級別一個數組),或者可以通過id創建查找表等。

+0

對不起,如果這是一個無知的問題。但是,我將如何組織這個在PHP? –

+0

biziclop的想法很好。你有三個層次。使用查詢獲取所有記錄,然後在其上運行循環,檢查'parentId'並將其分配給數組。我認爲沒有別的辦法。那麼,有 - 使用查詢獲得最高級別的記錄,然後循環,併爲每個頂級記錄找到它的孩子,然後爲每個孩子你需要一個查詢來找到它的孩子,等等。 – Pateman

+0

問題是我有無法控制數據庫。所以一切都必須通過PHP我的身邊完成。我已經做了一些尋找和遞歸php樹遍歷似乎是做到這一點的方式。沒有任何工作通過o.o –

0

我也有類似的問題,但經過大量的谷歌搜索和stackoverflowing :-) 我找到了我的答案.... 這是我的編碼方式。

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