2011-11-01 18 views
12

私はテーブルPeopleを持っています。私はすべての親と、その子のすべてをそれらのすぐ下に持つHTMLテーブルを表示したい。各親の子供のすべてを表示

_________ 
|People |_____________________________________________ 
|-------------------------------------------------------| 
| id  | parent | firstname  | lastname   | 
|-------------------------------------------------------| 
| 1  0  James   Donovan    | 
| 2  0  Jeffrey   Williams   | 
| 3  0  Emmit   Herring    | 
| 4  2  Carol   Williams   | 
| 5  2  Sarah   Williams   | 
| 6  1  Nikolai   Donovan    | 
|_______________________________________________________| 

予想される出力:

________________________________________________ 
|Jeffrey Williams        | 
|------------------------------------------------| 
| - Carol Williams        | 
| - Sarah Williams        | 
|________________________________________________| 
|James Donovan         | 
|------------------------------------------------| 
| - Nikolai Donovan        | 
|________________________________________________| 
|Emmit Herring         | 
|------------------------------------------------| 
|________________________________________________| 

がどのように反復処理するように設定右の結果を含む連想配列を構築するのですか?私は正しいSQLと正しいPHPが最終的な配列を構築するのに混乱しています。

具体的には、2つのMySQLテーブル間に階層関係を表示する方法がわかりません。私が知る限り、SQLの結果セットは多次元ではありません。 forループ内でSQLクエリを実行すると、パフォーマンスが低下します。あなたは何をしていますか?

私はMySQLで隣接リストの実装を探していますね。

この質問はすべてを2つのテーブルに分割できれば簡単ですが、残念なことに私はこの通常でないテーブル構造に固執する必要があります。

+0

jquery rightを使用できますか? – defau1t

+0

jQueryを使用して、各親の子のように単純なものを表示する必要があるのはなぜですか? PHPソリューションはありませんか? –

+0

@マーク私の質問は十分にはっきりしていないと思う。私は宿題のためにここにいません。私は質問を更新しました。 –

答えて

13

はそれを行うには、いくつかの方法があります。

1.明白1は、最初のすべての親のリストを取得し、その後、各親の子のために別のクエリを実行することですループ。あなたはこれが "パフォーマンスのためにひどい"と言っていますが、parentカラムにインデックスがあり、あなたのMySQLサーバが惑星の反対側に位置していないと仮定してはいけません。


2.あなたは本当にこれをしたい場合は、単一のクエリであり、あなたはそれ自体に対して、テーブルの上にLEFT JOINを使用することができます。

SELECT 
    p.id AS parent_id, 
    p.firstname AS parent_firstname, 
    p.lastname AS parent_lastname, 
    c.id AS child_id, 
    c.firstname AS child_firstname, 
    c.lastname AS child_lastname 
FROM 
    People AS p 
    LEFT JOIN People AS c ON c.parent = p.id 
WHERE p.parent = 0 
ORDER BY p.id 

ここでも、あなたは本当に、本当にparent列にインデックスが必要です。 ORDER BY句は、各親の子が一緒にソートされるようにするためのものです。あなたはそれを変更することができます。名前をアルファベット順に並べ替える場合は、p.lastname, p.firstname, p.id, c.lastname, c.firstname, c.idのようにします。 PHPでは、あなたはその後、結果をループに必要と、いつでも親IDの変更(とchild_*列がNULLの場合に対処するために覚えている)のような何か新しいヘッダーを印刷:

$res = mysql_query($sql); 
$last_parent_id = 0; 
while ($row = mysql_fetch_object($res)) { 
    if ($row->parent_id != $last_parent_id) { 
     // print parent header 
     $last_parent_id = $row->parent_id; 
    } 
    if ($row->child_id) { 
     // print child row 
    } 
} 

を3。

$res = mysql_query("SELECT * FROM People"); // add WHERE clauses if needed 
$names = array(); 
$parents = array(); 
$children = array(); 

while ($row = mysql_fetch_object($res)) { 
    $names[ $row->id ] = array($row->firstname, $row->lastname); 
    if ($row->parent == 0) { 
     $parents[] = $row->id; 
    } else { 
     if (!array_key_exists($row->parent, $children)) 
      $children[ $row->parent ] = array(); 
     $children[ $row->parent ][] = $row->id; 
    } 
} 

foreach ($parents as $parent_id) { 
    // print parent header 
    if (array_key_exists($parent_id, $children)) { 
     foreach ($children[ $parent_id ] as $child_id) { 
      // print child row 
     } 
    } 
} 

のPS:第三の選択肢は、単純なSELECT * FROM Peopleクエリですべての行をフェッチし、PHPのツリーを構築することです。実際にすべてテーブル内の親と子を表示したくない場合は、1つのファミリに属する​​ものだけをSQLでフィルタリングして、あまりにも多くのレコードを取得しないようにしてください。

0

JavaScriptで複数行配列を作成しないのはなぜですか?その後、配列をループして結果をDOMで取得します。

$res = mysql_query("SELECT PARENT"); 
while($row = mysql_fetch_assoc($res)) 
{ 

    // echo parent 

    $res2 = mysql_query("SELECT CHILD WHERE PARENT SOMETHING"); 
    while($row2 = mysql_fetch_assoc($res2)) 
    { 

    // echo child 
    } 
} 

をまたは、後でそれを維持し、フラグを格納します。

+1

ウェブサイトのユーザーはJavascriptを有効にする必要はありません。 JavascriptでDOMを操作しないで、親子関係のリストを表示できないのはなぜですか?私はPHPとMySQLを使用しています。 –

1

あなたがループ内でループを使用することができます。

$people = array(); 

$res = mysql_query("SELECT PARENT"); 
while($row = mysql_fetch_assoc($res)) 
{ 
    $people[] = array('is_parent' => true, 
        'info'  => $row); 

    $res2 = mysql_query("SELECT CHILD WHERE PARENT SOMETHING"); 
    while($row2 = mysql_fetch_assoc($res2)) 
    {  
    $people[] = array('is_parent' => false, 
         'info'  => $row2); 
    } 
} 

// later 

foreach($people as $person) 
{ 
    if($person['is_parent']) 
    { 
    // echo parent 
    } 
    else 
    { 
    // echo child 
    } 
} 
+0

もちろん可能ですが、私の質問で言及したように、そのようにすれば、テーブルが成長するにつれて容認できないパフォーマンス上の問題が発生します。 –

2

伝統的なアプローチによると、私はSQLで始まり、テーブルを結合することを考えます(この場合はテーブルとテーブルを残しても同じです)。

これは主にRDBMSを使用しているため、表の構造を処理し、データの一貫性について保証された方法でテーブルを結合する必要があるからです。

だから、のようなもので始まる:

SELECT 
     a.id parent_id, a.firstname parent_name, a.lastname parent_lastname, 
     b.id child_id, b.firstname child_firstname, b.lastname child_lastname 
FROM 
     People a LEFT OUTER JOIN People b ON a.id = b.parent 
WHERE 
     a.parent = 0; 

第二に、これを与える、あなたは「fetch_all」戦略を使用して選ぶべきです(例えば、mysqli PHPの拡張子を持つが、それはまたPDOで提供されています)全体の結果セットを2次元の連想配列にフェッチする1つの操作を行うことができます。

この時点でパスを選択できます。

All-PHP:PHPを使用して配列を歩いて、必要に応じて整理されたデータを表示するためのプレゼンテーションマークアップを直接作成してください。echoブラウザに向かってhtml文字列を入力してください。

AJAX:PHPスクリプトがAJAX経由で呼び出されている場合は、クエリ結果配列も同様に歩くことができますが、今回は呼び出しに応答するJSON構造を構築するために解釈しますそのように:シームレスそれを認識し、それを歩くことができjavascriptのあなたのクライアント側は、既存の空のテーブル骨格を移入するため

{ 
    "1": { 
     "id": 1, 
     "firstname": "James", 
     "lastname": "Donovan", 
     "children": { 
      "6": { 
       "id": 6, 
       "firstname": "Nikolai", 
       "lastname": "Donovan" 
      } 
     } 
    }, 
    "2": { 
     "id": 2, 
     "firstname": "Jeffrey", 
     "lastname": "Williams", 
     "children": { 
      "4": { 
       "id": 4, 
       "firstname": "Carol", 
       "lastname": "Williams" 
      }, 
      "5": { 
       "id": 5, 
       "firstname": "Sarah", 
       "lastname": "Williams" 
      } 
     } 
    }, 
    "3": { 
     "id": 3, 
     "firstname": "Emmit", 
     "lastname": "Herring", 
     "children": { } 
    } 
} 

このような表現は、データ交換のために良いだろう。確かにPHPをjson_encode()にすることができます。このような配列にリストラクチャするのではなく、配列を直接配列するのではなく、あなたがすでに持っているソリッドレコードセットのような配列表現よりはるかに遠くに行くことはありません。

最後に、all-mysqlソリューションは、探しているデータ構造を意図的に構築するストアドプロシージャを準備することです。最初の列に親のフルネーム、後続の列に子どものフルネーム(Emmit Herringのように子供がいない場合は空欄)を持つ、1つのファミリあたり1行。

PHPで結果セットをもう一度 "fetch_all"して、配列を歩くと完了します。

パフォーマンスに問題がある場合は、この最後のアプローチでは、サーバーが計算負荷とメモリ占有率で支払いを行ったと言わなければならない場合でも、最良の結果を保証する必要があります。膨大な量のデータを処理します。

関連する問題