今年初めての記事が質問になりました。
旧年からずっっっっっっっっっっと!プログラムしていますが、やればやるほど自分のレベルの低さにビビってしまって、新年早々泣きそうです(´;ω;)
んで、知り合いの先輩に質問したいので、記事にしました。
お題はこれ↓
MySQLからJoinした配列を組み直したい
概要
下記SQL文があるとします。
select `table_name01`.`id`, `table_name01`.`title`, `table_name02`.`table_02`, `table_name03`.`table_03` from `db_name`.`contents` AS `table_name01` inner join `db_name`.`table_name02` on (`table_name01`.`id` = `table_name02`.`id`) right join `db_name`.`table01_relations_table03` on (`table_name01`.`id` = `table01_relations_table03`.`table01_id`) inner join `db_name`.`table_name03` on (`table01_relations_table03`.`table03_id` = `table_name03`.`id`) ;
上のつながりはすっげーわかりにくいと思うので、図にすると下記になります。
こいつが引っ張ってくるデータはこんな感じ。
array( (int) 0 => array( 'table_name01' => array( 'id' => '3', 'title' => '俺、ツインテールになります。1話 テイルレッドが可愛い', ), 'table_name02' => array( 'table_02' => 'yahoo' ), 'table_name03' => array( 'table_03' => 'TV' ) ), (int) 1 => array( 'table_name01' => array( 'id' => '1', 'title' => '3DS『モンスターハンター4G』 プロモーション映像4', ), 'table_name02' => array( 'table_02' => 'yahoo' ), 'table_name03' => array( 'table_03' => 'モンスターハンター' ) ), (int) 2 => array( 'table_name01' => array( 'id' => '1', 'title' => '3DS『モンスターハンター4G』 プロモーション映像4', ), 'table_name02' => array( 'table_02' => 'yahoo' ), 'table_name03' => array( 'table_03' => 'アニメ' ) ) )
このデータを下記のようにしたいのです。
array( (int) 0 => array( 'id' => '3', 'title' => '俺、ツインテールになります。1話 テイルレッドが可愛い', 'table_02' => 'yahoo' 'table_03' => 'TV' ), (int) 1 => array( 'id' => '1', 'title' => '3DS『モンスターハンター4G』 プロモーション映像4', 'table_02' => 'yahoo' 'table_03' => array( (int) 0 => 'モンスターハンター', (int) 1 => 'アニメ' ) ) )
理由としては、sqlからもらったデータをそのまま使うとループがすごいことになるので、できれば組み替えたいのです。
また、結果を確認するとarray(1)とarray(2)の結果だけ、table_03の値以外、重複しています。実はこれも悩ませた一つで、これについては、他の連想の重複を消した上で、table_03は配列にしたい。これがめっちゃめんどくせぇ(´Д`)
その他理由として、phpを今使うにあたり、このようなjoinデータはいっぱいでてくると思うんです。なので、組み替えの練習をしているところでした。
自分の出した結果(´;ω;)
一応下記のようにコードを書いたら取り出せました。。。
流れとして
- 最初の親indexでforeach()します。
- んで、子のindexデータの最後の葉データをarray_walk_recursive()を使って、普通の連想配列にします。
- 普通の連想配列にしたら、最後に$result_arrayにarray_push()(配列を追加)します。
- また、途中でtable_03以外の値が同じ連想配列はtable_03を配列化して、重複を取り除かなければいけない。。。
- わかりにくいけど、table03の値を追加するindex番号はRecursiveIteratorIteratorを使って判断しています。
<?php ... // 整列した配列を格納したい変数です $result_array = array(); // $sql_dataには先程のsql結果のデータが入っています。 foreach($sql_data as $k => $v) { $tmp_array_save = array(); array_walk_recursive($v, function(&$value, $key) use (&$tmp_array_save) { $tmp_array_save[$key] = $value; }); // 初回のみ$result_arrayは連想配列ではないため、比較するとエラーになる // なので、配列が空であれば0なので、条件分岐でfalse(初回追加となる) if (count($result_array)) { // 返す配列にすでに存在しているかチェック $contents_id_array = Hash::extract($result_array, '{n}.contents_id'); if (in_array($tmp_array_save['contents_id'], $contents_id_array)) { // 存在している場合は重複なので、追加 // contents_idから逆引きして格納が必要な配列番号を探す $iterator = new RecursiveIteratorIterator( new RecursiveArrayIterator($result_array), RecursiveIteratorIterator::SELF_FIRST ); // table03が追加される配列番号を格納する変数 $add_index_number = ''; foreach ($iterator as $iterate_key => $iterate_leaf) { if (is_array($iterate_leaf)) { $add_index_number = $iterate_key; } } // table03の値が重複していないかチェック、していなければ追加 if (! in_array($tmp_array_save['table_03'], $result_array[$add_index_number])) { $tmp_tags_data = $result_array[$add_index_number]['table_03']; $result_array[$add_index_number]['table_03'] = array(); array_push($result_array[$add_index_number]['table_03'], $tmp_array_save['table_03'], $tmp_tags_data); } } else { // 存在していない場合は新規追加 array_push($result_array, $tmp_array_save); } } else { // 初回の追加 array_push($result_array, $tmp_array_save); } } // 確認コード dump($result_array);
まとめ
説明して思ったんだけど、これってすごく説明しづらくない? あと俺のコードめちゃめちゃわかりにくい・・・。
プログラムできない俺が言ってもアレなんですが、プログラムって難しい組み方しちゃいけないと思うの(´・ω・)
読み辛いコードを書くこと自体あんましよくないと思います。。。orz
助けて先輩!!!(´;ω;)