3

無制限のサブカテゴリメニューを作成するためにmysqlデータベースからデータを抽出する方法を探しています。メニューには約1500のカテゴリがあり、次の形式でデータベーステーブル(メニュー)に保存されます。

category_id、category title、parent_id

すべてのデータを配列に入れるために1つのmysqlクエリを実行したいと思います。

$menu_list =array();

$query = mysql_query("SELECT * FROM menu ORDER BY category_id ASC");

if(mysql_num_rows($query) != 0) {
        while($row = mysql_fetch_array($query)){
              $category_id = $row['category_id'];
              $title = $row['category_title'];
              $parent_id = $row[parent_id'];
              $menu_list[] = array($category_id,$title,$parent_id);
        }
}

これは、データを配列に変換するために現在使用しているコードです。

次に、配列をループしてメニューを作成する必要があります。

次に、すべてのサブカテゴリを非表示にして、jqueryで展開します(このビットは問題なく実行できます)

私が抱えている問題は、配列を調べてデータを正しい順序で表示することです。メニューには無制限のサブカテゴリがあるため、データを取得するには再帰関数である必要があります。ここで多くの例を実行しましたが、データの表示方法がわかりません。

私は今で終わる必要があります:

main item
  sub cat
  sub cat
      sub cat 
          sub cat 
main item
   sub cat
main item
main item
   sub cat
       sub cat
          sub cat
             sub cat
             sub cat

etc...  

各カテゴリが独自のdivにある場合、各カテゴリを編集できる必要があります(つまり、必要に応じてタイトル名と位置)。サブカテゴリのベースとなる場所を変更すると、ページをすばやく更新すると、メニューが新しい順序で再読み込みされます。 ..

最終的にはこれをドラッグアンドドロップにしたいと思いますが、それは後日行われます。

これで十分に説明できたと思います。

前もって感謝します..


そのため、問題が再び発生しました...別のmysql selectを呼び出すajaxの方法は、CMSセクションでは時々しか使用されなかったため、問題ありませんでした。しかし今、私たちはフロントエンドに到達しました。ページが表示されるたびに、メニューの最初の3つのレベルが多数のmysqlリクエストを使用してプルされます。カテゴリが大きくなるにつれて、これにより1600以上のカテゴリがそれぞれ何度もプルされ、1日あたり1000回の訪問でも、1日あたり1000000を超えるSQLリクエストが発生します。したがって、カテゴリを配列にプルしてから、再帰的に配列を調べる必要があると思います。

私は上記の解決策を見てきましたが、それらは紙の上で機能しているように見えますが、実際には機能していません。

誰かが私に別の解決策を与えることを試みることができるならば、それはありがたいです。

私のデータベースに要約すると、私は:id、category_name、parent_idを持っています

現在、mysqlでPDOを使用しており、セキュリティを強化するためのプリペアドステートメントを使用しています。

前もって感謝します..

4

6 に答える 6

3

ここにあなたが必要とするコードがあります

category_id AS id 、カテゴリ タイトル AS kategori 、parent_id AS kid

function countsubcat($pid)
{

   $r=mysql_query("select count(kid) AS say from meskat where kid='$pid' limit 1");

   $rw=mysql_fetch_array($r);

   return $rw['say'];

}

function listmenu($pid = 0)
{

   $res = mysql_query("select id,kategori,kid from meskat where kid='$pid'");

   while($cat=mysql_fetch_array($res))

   {

     echo '<li>';

     print'<a href="#">'.$cat['kategori'].'</a>';

     if(countsubcat($cat['id'])>0)

     {

      print'<ul>';

         listmenu($cat['id']);

      print'</ul>';

     }
   echo '</li>';

   }

}

echo '<ul>';

listmenu(0); //starting from base category

echo '</ul>';`
于 2012-09-26T18:32:53.403 に答える
1

MySQL では、これには多くのクエリが必要です。各レベルに 1 つと、最低でも 1 つです。

  1. トップレベルのカテゴリをすべて取得し、それらをフォレスト (ツリーのグループ) のルート ノードとして使用します。
  2. それらのいずれかの子であるすべてのカテゴリを取得します。
  3. これらの各カテゴリを子として親ノードに追加します
  4. まだ子がいる場合はステップ 2 に進み、そうでない場合は停止します。

深さ優先のウォークスルーを実行して、(おそらく) html 表現 (ネストされたリストなど) に変換するツリーで終わるもの。

実行できる最適化がいくつかあります。子レベルを親 ID で並べ替えると、子の連続ブロックを想定できます。つまり、正しい親を見つけるために多くの検索を行う必要はなく、親 ID の変更を確認するだけです。

ID でインデックス付けされた現在の最下位レベルのカテゴリのリストを維持すると、フォレストの作成を高速化できます。

ステップ 2 と 4 をオーバーラップすると、n+1 クエリ (n はレベルの数) しか実行されないため、さらに子をチェックすると、次のレベルの子も取得されます。

メモリに関しては、これはツリーに必要なメモリに加えて、最下位レベルのルックアップ テーブルと現在の親 ID を使用します。

構築アルゴリズムはかなり高速で、カテゴリの数に比例してスケーリングします。

また、この方法は、サイクルのあるデータ (ルート ノードがない) を取得しないため、データの破損したセクションをうまく回避します。

MySQL がクエリをコンパイルしてキャッシュするため、子クエリにプリペアド ステートメントを使用することもお勧めします。これにより、ネットワークを介して新しいデータのみが送信されるため、操作が高速化されます。

いくつかの概念を理解していない場合は、標準的な用語を使用しようとしているので、ウィキペディアを参照することをお勧めします。

于 2012-07-23T23:38:23.910 に答える
0

テーブル構造を変更できますか? その場合は、ネストされたセット モデルを確認できます(リンクには説明と実装の詳細が含まれています。ネストされたセット モデルまでスクロールします)。ノードの挿入と削除はより複雑になりますが、1 回のクエリでツリー全体を取得できます。

于 2012-07-24T00:10:07.553 に答える
0

任意のカテゴリが true であると仮定できる場合category_id > parent_id、メニューをマルチレベル配列として表し、ネストされた HTML リストとしてレンダリングする次の再帰関数が機能します。

$menu = array();

$query = mysql_query("SELECT category_id, category_title, parent_id FROM menu ORDER BY category_id ASC");
if(mysql_num_rows($query) != 0) {
        while($row = mysql_fetch_assoc($query)) {
            if(is_null($row['parent_id']))
                $menu['children'][] = $row;
            else
                add_to_menu(&$menu,$row);
        }
}

function add_to_menu($menu,$item) {
    if(isset($menu['children'])) {
        foreach($menu['children'] as &$child) {
            if($item['parent_id'] == $child['category_id']) {
                $child['children'][] = $item;
            } else {
                add_to_menu(&$child,$item);
            }
        }
    }
}

function render_menu($menu) {
    if(isset($menu['children'])) {
        echo '<ul>';
        foreach($menu['children'] as &$child) {
            echo "<li>";
            echo $child['category_id']." : ".$child['category_title'];
            if(isset($child['children'])) {
                render_menu(&$child);
            }
            echo "</li>";
        }
        echo '</ul>';
    }
}

render_menu($menu);
于 2012-07-24T00:01:28.847 に答える
0

したがって、さまざまなソリューションでさまざまな試みを行った後、実際にjqueryとajaxロードを使用して次のレベルを取得しました。

私のメイン カテゴリはすべて 1 の親を持ちます。ショップでは、親 ID として 1 を持つすべてのカテゴリに対して mysql スキャンを実行します。

これにより、メインのカテゴリが表示されます。サブカテゴリがある場合は、各メインカテゴリにフォルダアイコンを追加しました。また、そのカテゴリの ID を持つ空白の div を挿入しました。

フォルダーがクリックされると、php スクリプトへの ajax 呼び出しが行われ、その親を持つすべてのカテゴリーが検索されます。これらはparent_id divに追加されます。

この inturn は、カテゴリ (サブカテゴリを示す css パディングを使用) を追加し、サブカテゴリと、category_id を持つ別の空白の div がある場合はフォルダー記号を再度追加します。

クライアントが必要とするカテゴリとサブカテゴリの数だけ、これを続けることができます。

さらに一歩進んで、カテゴリ/サブカテゴリに編集アイコンを追加して、カテゴリを移動または変更できるようにしました。

このためのサンプル コードが必要な場合は、お知らせください...

于 2012-08-25T12:00:43.513 に答える