質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

3回答

24346閲覧

PHPでDBから読み出したデータを、HTMLの表(table)出力するスマートな方法

sanzui

総合スコア19

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

1グッド

4クリップ

投稿2017/02/21 12:30

###前提・実現したいこと
要約すると「DBから取得した配列データを加工・集計して使いたいが、何度もループで回したり再度配列に入れ直して処理するのは避けたい」

PHPでDBから読みだしたデータを、HTMLのtableに吐き出します。
この際、HTMLのテーブルで縦に同項目があった場合はrowspanで結合するようにしたいです。(下記ソースの「大分類」を同じ名前で結合)
また、縦一列全ての欄が空白の場合は、その列ごと表示しないようにしたいです。(下記ソースの「備考」列を消す)

以下、行数・列数を簡素化したデータになります。

HTML

1<table> 2 <thead> 3 <tr> 4 <th>大分類</th> 5 <th>小分類</th> 6 <th>品名</th> 7 <th>価格</th> 8 <th>備考</th> 9 </tr> 10 </thead> 11 <tbody> 12 <tr> 13 <td rowspan="2">分類A</td> 14 <td>小分類1</td> 15 <td>商品A</td> 16 <td>10,000</td> 17 <td></td> 18 </tr> 19 <tr> 20 <td>小分類2</td> 21 <td>商品B</td> 22 <td>30,000</td> 23 <td></td> 24 </tr> 25 <tr> 26 <td>大分類B</td> 27 <td>小分類3</td> 28 <td>商品C</td> 29 <td></td> 30 </tr> 31 </tbody> 32</table>

###発生している問題・エラーメッセージ
通常ですと、読みだしたデータをforeachループで一行ごと読みだしながら処理を行いますが、今回rowspanで結合するという事で、数を数える必要性があります。
1ループで処理できるスマートな方法が、考え付きません。全データをもう多次元配列に入れ直してその列の全項目を再度上から下までチェックさせる方向の処理は避けたいです。(中学生の頃はfor文二つ重ねてループさせたりしてましたが )

※見た目を気にする案件で、同じ項目が縦に並んだり「〃」等の記号での表示はできないものとお考え下さい。

###現在の単純な処理
実際はこれより列が多くここにそれぞれの値を変換したり処理が追加されます。

PHP

1$html = ''; 2foreach($arrData as $data) { 3 $line = '<tr>'; 4 $line .= '<td>' . $data['CATEGORY1'] . '</td>'; 5 $line .= '<td>' . $data['CATEGORY2'] . '</td>'; 6 $line .= '<td>' . $data['PRICE'] . '</td>'; 7 $line .= '<td>' . $data['BIKO'] . '</td>'; 8 $html .= $line . '</tr>'; // $htmlに1行分追加 9} 10$html .= '<table>' .$html. '</table>';
pac894398👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

値が同じ項目を探すループと出力するループの2つは必要だと思います。コードは適当ですが、考え方の参考になれば。

PHP

1// $arrData = 元データ; 2$tmpArray = []; 3$checkData = [ 'a' => false, 'b' => false, 'c' => false ]; // 行フラグ保存用 4$countData = [ 'a' => [ '', 0 ], 'b' => [ '', 0 ], 'c' => [ '', 0 ] ]; // 「何個同じ項目があるか」を数える用 5 6// 逆順にする 7$reversedArray = array_reverse( $arrData ); 8 9// データを数えながら作成する 10foreach( $reversedArray as $data ) { 11 $tmp = []; 12 $a_text = ''; 13 $a_count = $countData[ 'a' ][ 1 ]; 14 if ( isset( $data[ 'a' ] ) ) { 15 $a_text = $data[ 'a' ]; 16 if ( $countData[ 'a' ][ 0 ] === $a_text ) { 17 $a_count += 1; 18 } else { 19 $a_count = 0; 20 } 21 $checkData[ 'a' ] = true; // 1個でも入っていたら行を表示 22 } 23 $countData[ 'a' ][ 0 ] = $a_text; 24 $countData[ 'a' ][ 1 ] = $a_count; 25 $tmp[ 'a' ] = [ $a_text, $a_count ]; // [ 値, 同じ値のカウント ] 26 /* 2728 */ 29 $tmpArray[] = $tmp; 30} 31 32echo '<table>'; 33array_reduce( 34 array_reverse( $tmpArray ) // 戻す 35 , function ( $carry, $key ) use ( $checkData ) { 36 echo '<tr>'; 37 // 行にデータがあって、前の行のa_countが「0」のものを出力する 38 if ( $checkData[ 'a' ] && $carry[ 'a' ] === 0 ) { 39 $tmp = '<td'; 40 if ( $key[ 'a' ][ 1 ] > 0 ) { 41 $tmp .= ' rowspan="'.( $key[ 'a' ][ 1 ] + 1 ).'"'; 42 } 43 echo $tmp.'>'.$key[ 'a' ][ 0 ].'</td>'; 44 } 45 /* 4647 */ 48 echo '</tr>'; 49 $carry[ 'a' ] = $key[ 'a' ][ 1 ]; 50 return $carry; 51 } 52 , [ 'a' => 0, 'b' => 0, 'c' => 0 ] 53); 54echo '</table>'; 55// 未テスト

【PHP: array_reverse - Manual】
http://php.net/manual/ja/function.array-reverse.php

【PHP: array_reduce - Manual】
http://php.net/manual/ja/function.array-reduce.php

投稿2017/02/21 20:29

kei344

総合スコア69398

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sanzui

2017/03/10 02:28

ありがとうございます。 試した事のなかった方法で、他の箇所でも活用させていただきました。
guest

0

ベストアンサー

#DB 定義、サンプルデータ

sql

1CREATE TABLE `sample` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `category` int(11) NOT NULL DEFAULT '0', 4 `sub_category` int(11) DEFAULT NULL, 5 `name` varchar(32) NOT NULL DEFAULT '', 6 PRIMARY KEY (`id`) 7) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 8 9INSERT INTO `sample` (`id`, `category`, `sub_category`, `name`) 10VALUES 11 (1,1,11,'name1'), 12 (2,1,12,'name2'), 13 (3,1,13,'name3'), 14 (4,2,21,'name4'), 15 (5,2,22,'name5'), 16 (6,3,30,'name6');

#サンプルコード

html

1<?php 2ini_set('display_errors', true); 3error_reporting(E_ALL); 4 5$dsn = 'mysql:host=localhost;dbname=sample;charset=utf8;'; 6$username = 'root'; 7$password = 'password'; 8$options = [ 9 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION 10 , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC 11]; 12$oPdo = new PDO($dsn, $username, $password, $options); 13 14$sql = 'SELECT `id`, `category`, `sub_category`, `name` '; 15$sql .= 'FROM `sample` '; 16$sql .= 'WHERE 1 '; 17$sql .= 'ORDER BY `category` ASC, `sub_category` ASC '; 18$stmt = $oPdo->prepare($sql); 19$stmt->execute(); 20 21$rows = $stmt->fetchAll(); 22 23$formattedArray = []; 24foreach ($rows as $row) { 25 $category = $row['category']; 26 $formattedArray[$category][] = $row; 27} 28?> 29<!DOCTYPE HTML> 30<html lang="ja"> 31 <head> 32 <meta charset="UTF-8"> 33 <title></title> 34 <style type="text/css"> 35 table { 36 border-collapse: collapse; 37 } 38 td, th { 39 border: 1px solid #CCC; 40 } 41 </style> 42 </head> 43 <body> 44 <div> 45 <table> 46 <thead> 47 <tr> 48 <th>category</th> 49 <th>subcategory</th> 50 <th>id</th> 51 <th>name</th> 52 </tr> 53 </thead> 54 <tbody> 55 <?php foreach ($formattedArray as $category => $rows) : ?> 56 <tr> 57 <td rowspan="<?= count($rows); ?>"><?= $category ?></td> 58 <?php foreach ($rows as $i => $row) : ?> 59 <?php if ($i > 0) : ?> 60 <tr> 61 <?php endif; ?> 62 <td><?= $row['sub_category'] ?></td> 63 <td><?= $row['id'] ?></td> 64 <td><?= $row['name'] ?></td> 65 <?php endforeach; ?> 66 </tr> 67 <?php endforeach; ?> 68 </tbody> 69 </table> 70 </div> 71 </body> 72</html>

投稿2017/02/22 17:42

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

kei344さんのarray_reverseを使うという発想が目から鱗だったので、練習がてらしてみました。

PHP

1$arrData = [["c"=>"分類1","v"=>"値1"],["c"=>"分類1","v"=>"値2"],["c"=>"分類2","v"=>"値3"]]; 2$reversedArray = array_reverse( $arrData ); 3 4$beforeCategory=null; 5$rowspan=1; 6 7$tmp=""; 8foreach($reversedArray as $data){ 9 if($beforeCategory!=null){ 10 if(strcmp($beforeCategory, $data['c'])!=0){ 11 $tmp = "<tr>".($rowspan>1 ? "<td rowspan=\"".$rowspan."\">" : "<td>").$beforeCategory."</td>".$beforeLine."</tr>\n".$tmp; 12 $rowspan=1; 13 }else{ 14 $tmp = "<tr>".$beforeLine."</tr>\n".$tmp; 15 $rowspan++; 16 } 17 } 18 $beforeCategory = $data['c']; 19 $beforeLine ="<td>".$data['v']."</td>"; 20} 21$tmp = "<tr>".($rowspan>1 ? "<td rowspan=\"".$rowspan."\">" : "<td>").$beforeCategory."</td>".$beforeLine."</tr>\n".$tmp; 22 23echo "<table>\n"; 24echo $tmp; 25echo "</table>";

また、縦一列全ての欄が空白の場合は、その列ごと表示しないようにしたいです。(下記ソースの「備考」列を消す)

これに関しては「全てのデータを確認せずに全てのデータで空欄かどうかを判別する」というのがそもそも無理な話なので、結局確認用と出力用で2回ループを回すのが一番スマートな方法だと思います。
(データ取得時にSELECT句で副問い合わせなどして強引に何とかする手があるかもしれませんが・・・)

投稿2017/02/22 02:04

KaedeKazane

総合スコア408

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問