2017-01-11 8 views
0

私はこの単純なテーブルを持っているとしましょう。ここでpos_levelは位置のレベルで、pos_underはその上の位置のPIDです。PHPを使用してMySQLクエリ結果をネストされた配列として取得するにはどうすればよいですか?

レベル1では、私には「ゼネラルマネージャー」と「スーパーバイザー」があります。

レベル2では、「ゼネラルマネージャ(PID:1)」の下に「Asst。 (PID:2) ':'マーケティング 'の下にある[マネージャ]をクリックします。

レベル3では、[Asst。 (PID:3) ':' Sales '&' Purchase '(マーケティング(PID:2):なし)私はこのような結果として、ネストされた配列を取得して

+-----+-----------------+-----------+-----------+ 
| PID | pos_name  | pos_level | pos_under | 
+-----+-----------------+-----------+-----------+ 
| 1 | General Manager |  1  |  0  | 
| 2 | Supervisor  |  1  |  0  | 
| 3 | Asst. Manager |  2  |  1  | 
| 4 | Sales   |  3  |  3  | 
| 5 | Purchase  |  3  |  3  | 
| 6 | Marketing  |  2  |  2  | 
+-----+-----------------+-----------+-----------+ 

今どのように私は、クエリを作成します:

Array 
(
    [0] => Array 
     (
      [pos_level] => 1 
      [pos_name] => General Manager 
      [pos_under] => Array 
       (
        [0] => Array 
         (
          [pos_level] => 2 
          [pos_name] => Asst. Manager 
          [pos_under] => Array 
           (
            [0] => Array 
             (
              [pos_level] => 3 
              [pos_name] => Sales 
             ) 

            [1] => Array 
             (
              [pos_level] => 3 
              [pos_name] => Purchase 
             ) 

           ) 

         ) 

       ) 

     ) 

    [1] => Array 
     (
      [pos_level] => 1 
      [pos_name] => Supervisor 
      [pos_under] => Array 
       (
        [0] => Array 
         (
          [pos_level] => 2 
          [pos_name] => Marketing 
          [pos_under] => Array 
           (
           ) 

         ) 

       ) 

     ) 

) 

を私は複数のクエリを使用して、結果を使用してarray_push使用して試してみましたが、私は次のように持っています約100 + pos_nameと私はそれが面倒だと思う、私はまた、各レベルの複数のテーブルを使用して試して、各レベルのクエリを実行し続けるためにループを使用してみましたが、私は1つのテーブルを使用することができ、私のアプリケーションでさらに使用するために上記のネストされた配列としての結果。

すべての回答、コメント、および提案は非常に歓迎されています。ありがとうございました。

+1

どのように多くのレベルすることができますあります?また、MySQLで期待している実際の出力を表示してください。 –

+1

ネストした配列を自分で構築する必要があります。私はどのPHP関数もSQLクエリからマルチレベル配列を返し、SQLクエリは2次元のテーブルのような構造を返すとは思わない。 – yivi

+0

私は一般的に、あなたが従うアプローチは良いものであるとは考えていません。それはスケールされないためです!データベースからすべてのエントリを取り出し、それらを単一の階層的な配列にパックしようとします。つまり、各エントリの複数のコピーをメモリに作成します。エントリ数が増えるとどうなりますか?あなたは常に、最終的には失敗に終わるスクリプトのメモリ消費を常に増加させています。 – arkascha

答えて

0

コメントの上で述べたように、私が一般的に言っているように、あなたが従うアプローチは良いものだとは思えません。それはスケールされないためです!データベースからすべてのエントリを取り出し、それらを単一の階層的な配列にパックしようとします。つまり、各エントリの複数のコピーをメモリに作成します。エントリ数が増えるとどうなりますか?あなたは常に、最終的には失敗に終わるスクリプトのメモリ消費を常に増加させています。

しかし、私は挑戦を受け入れ、参照の助けを借りて巧みにそのような入れ子構造を構築する方法の小さなデモンストレーションを実装しました。このような参照は、ネストされた構造の作成を簡素化するだけでなく、エントリが何度も値によってコピーされるのを防ぐことによって、メモリの占有面積を削減します。しかしこれはではなく、は、上記のこのアプローチで一般的なスケーリングの問題を解決します。

私はあなたのアプローチを少し変更し、エントリの下にエントリを保持する新しいプロパティ "pos_over"を導入するよう自由を取った。そのため、二つの理由:

  1. 通常、元の利用可能なデータを削除するのは良い考えではありませんし、特に変更された意味
  2. 用語「pos_under」の意味でそれを置き換えることではないの下に記述することで、他のどのような指定されたエントリが配置されます。しかし、 "上側"のエントリーの観点からは、 "下"のものは "pos_under"によって参照されるべきではありません。それはその言葉の本来の意味に反するでしょう。

次のコードないはデモンストレーションの目的のためにデータベースに依存しません。代わりに、CSV文字列から生データを読み取り、それを解析します。所望の構造体構造の実際の建物には、さらにコメントが付けられている。また、コードでは、元のデータが宣言された後にのみ、他のエントリを参照することを期待していることに注意してください。したがって、上から下に処理された場合、別のエントリの下の各エントリは、他のエントリがすでに存在することを期待できます。実際のコードは、ネストされた構造は、単なる12本の巧妙なラインで構成されていることを構築することを

ノート、...

<?php 

// the raw CSV data 
$csvText = <<<CSV 
PID|pos_name|pos_level|pos_under 
1|General Manager|1|0 
2|Supervisor|1|0 
3|Asst. Manager|2|1 
4|Sales|3|3 
5|Purchase|3|3 
6|Marketing|2|2 
CSV; 

// praparation of CSV data 
foreach (explode("\n", $csvText) as $csvRow) { 
    $csvData[] = str_getcsv($csvRow, '|'); 
} 
$csvTitle = array_shift($csvData); 

$table = []; 
foreach ($csvTitle as $titleKey=>$titleValue){ 
    foreach ($csvData as $csvRow=>$csvColumn) { 
     foreach ($csvColumn as $csvKey=>$csvValue) { 
      $table[$csvRow][$csvTitle[$csvKey]] = $csvValue; 
     } 
    } 
} 

// creation of the structure 
$catalog = []; 
$structure = []; 
foreach ($table as $key=>&$entry) { 
    $entry['pos_over'] = []; 
    if ($entry['pos_under'] == 0) { 
     $structure[] = &$entry; 
     $catalog[$entry['PID']] = &$structure[count($structure)-1]; 
    } else { 
     $catalog[$entry['pos_under']]['pos_over'][] = &$entry; 
     $catalog[$entry['PID']] = &$catalog[$entry['pos_under']]['pos_over'][count($catalog[$entry['pos_under']]['pos_over'])-1]; 
    } 
} 

// demonstration output 
print_r($structure); 

上記実験の出力は、次のとおりです。

Array 
(
    [0] => Array 
     (
      [PID] => 1 
      [pos_name] => General Manager 
      [pos_level] => 1 
      [pos_under] => 0 
      [pos_over] => Array 
       (
        [0] => Array 
         (
          [PID] => 3 
          [pos_name] => Asst. Manager 
          [pos_level] => 2 
          [pos_under] => 1 
          [pos_over] => Array 
           (
            [0] => Array 
             (
              [PID] => 4 
              [pos_name] => Sales 
              [pos_level] => 3 
              [pos_under] => 3 
              [pos_over] => Array 
               (
               ) 

             ) 

            [1] => Array 
             (
              [PID] => 5 
              [pos_name] => Purchase 
              [pos_level] => 3 
              [pos_under] => 3 
              [pos_over] => Array 
               (
               ) 

             ) 

           ) 

         ) 

       ) 

     ) 

    [1] => Array 
     (
      [PID] => 2 
      [pos_name] => Supervisor 
      [pos_level] => 1 
      [pos_under] => 0 
      [pos_over] => Array 
       (
        [0] => Array 
         (
          [PID] => 6 
          [pos_name] => Marketing 
          [pos_level] => 2 
          [pos_under] => 2 
          [pos_over] => Array 
           (
           ) 

         ) 

       ) 

     ) 

) 
+0

あなたの素晴らしい答えをありがとうございます、ごめんなさい、配列内にpos_overキーを使用していたはずですが、私は単純な解決法いくつかの他の関数では、この配列(ループを使用して作成されたもの)を一度にループする必要があるので、MySqlクエリを使用しています。とにかくあなたのループ方法を使用しようとします。ありがとう! – Charas

+0

@Charas示されたアプローチの重要な側面はループではなく、些細なことです。エントリの_copies_の代わりに_references_を使用しています... – arkascha

関連する問題