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

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

ただいまの
回答率

90.03%

mysql に登録した商品マスターのカテゴリー名をPHPでリストメニューを作りたい。(難易度5)

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,036

daisaku64

score 12

前提・実現したいこと

少し難しいみたいですが
mysql に登録した商品マスターのカテゴリー名をPHPでリストメニューを作りたい。(Part.2)
初心者です。

発生している問題・エラーメッセージ

データベスからカテゴリー名を読み込み、数種類の変数に格納してPHPでリストメニューを作りたい

データ↓
商品コード(hs_id):カテゴリー1(ct_03) : カテゴリー2(ct_04)
1001 : A : AA
1002 : A : BB
1003 : A : BB
1004 : A : CC
1005 : B : BB
1006 : B : BB
1007 : B : CC

というデータで Aというカテゴリー名とBというカテゴリー名を取得して

<ul>
<li>A
<ul>
<li>AA</li>
<li>BB</li>
<li>CC<li>
</ul>
</li>
<li>B
<ul>
<li>BB</li>
<li>CC<li>
</ul>
</li>
</ul>

というリストを表示したいのですが。
group を使うと

<ul>
<li>A
<ul>
<li>AA</li>
<li>BB</li>
<li>CC<li>
</ul>
</li>
<li>B
</li>
</ul>

となります。確かにGROUPだとトータルでカウントするだけなので....

カテゴリー1 (A) のAA,BB,CCは出てきますが (B)のBB,CCが表示されません
GROUP だと最初 (A) のAA,BB,CCでカウントされてしまい、(B)には残りません
GROUP の使い方を調べていますが他の方法があるのでしょうか?

サンプルソースは4段階の入れ子になっていて
一番上のデータだけ表示されリストの2行目以降が何も出ません

PHPでswitch : case などで振り分けが必要なんでしょうか

sql文の裏技があるのかmないのか...

どなたか教えてください
よろしくお願い致します。

エラーメッセージ

該当のソースコード

<?PHP
require_once("./js/nic_MYDB.php");
$pdo = db_connect();

// 01-02 ct-0102
$sql= "SELECT ct_02,COUNT(*) AS count FROM products_table where hs_id >= 1001 AND hs_id <= 1999 GROUP BY ct_02 ORDER BY hs_id ASC ";
$stmh0102 = $pdo->query($sql);

// 01-03 ct-0103
$sql= "SELECT ct_03,COUNT(*) AS count FROM products_table where hs_id >= 1001 AND hs_id <= 1999 GROUP BY ct_03 ORDER BY hs_id ASC ";
$stmh0103 = $pdo->query($sql);

// 01-04 ct-0104
$sql= "SELECT ct_04,COUNT(*) AS count FROM products_table where hs_id >= 1001 AND hs_id <= 1999 GROUP BY ct_04 ORDER BY hs_id ASC ";
$stmh0104 = $pdo->query($sql);
?>

<nav id="dd">
<ul>
<li class="font18"><a href="http://www.nikkohm.com/test/#" class="active">Part Search</a>
    <!-- 01 -->
  <ul class="level1" style="display: block;">
    <!-- 01-01 -->
  <li><a href="#" class="item-arrow">Power</a>

<?PHP
echo '<!-- 01-02 -->';
echo "<ul class=\"level2\" style=\"display: none;\">";
while ($row = $stmh0102->fetch(PDO::FETCH_ASSOC)) {
    echo "<li><a href=\"#\" class=\"item-arrow\">";
    echo htmlspecialchars($row["ct_02"]);
    echo "</a>";

    echo "<!-- 01-03 -->";
    echo "<ul class=\"level2\" style=\"display: none;\">";
    while ($row = $stmh0103->fetch(PDO::FETCH_ASSOC)) {
        echo "<li><a href=\"#\" class=\"item-arrow\">";
        echo htmlspecialchars($row["ct_03"]);
        echo "</a>";

        echo "<!-- 01-04 -->";
        echo "<ul class=\"level2\" style=\"display: none;\">";
        while ($row = $stmh0104->fetch(PDO::FETCH_ASSOC)) {
            echo "<li><a href=\"#\" class=\"item-arrow\">";
            echo htmlspecialchars($row["ct_04"]);
            echo "</a>";
            echo "</li>";
        }
        echo "</ul><!-- 01-04 -->";
        echo "</li>";
    }
    echo "</ul><!-- 01-03 -->";
    echo "</li>";
}
echo "</ul><!-- 01-02 -->";
?>

  </li><!-- 01-01 -->
  <!-- 01-02 -->
  <li><a href="#" class="item-arrow">Shunt</a>
  </li><!-- 01-02 -->
  </ul><!-- 01 -->
</li><!-- Part Search -->
</ul>
</nav>

試したこと

PHPでswitch : case などで振り分けが必要だと思いますが、sql文 だけで良い方法があれば

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

sql文の裏技があるのかmないのか...

⇒通常のやり方は他の方にお任せするとして、
裏ワザということであれば、以下の抽出結果をechoするだけでできます。

裏ワザとはいえ保守性は最悪なので、オススメしませんが、
記載されているPHPの作り的に既に保守性は低いので、
以下のようなSQLが追加されたところで、
保守性は対して変わらないような気はしています。

保守性や作りこみ方については「MVC」についてご理解されることをお勧めします。
(フレームワークを使いましょう、と言っているわけではございません)

create table products_table (
 hs_id int not null,
 ct_02 varchar(10),
 ct_03 varchar(10),
 ct_04 varchar(10)
);

insert into products_table
values
 (1001,'ct_02','A','AA')
,(1002,'ct_02','A','BB')
,(1003,'ct_02','A','BB')
,(1004,'ct_02','A','CC')
,(1005,'ct_02','B','BB')
,(1006,'ct_02','B','BB')
,(1007,'ct_02','B','CC')
;

-- 抽出SQL
select    REPLACE(
                concat(
                        '<li>'
                    ,    ifnull( T1.ct_03, '' )
                    ,    '<ul><li>'
                    ,    REPLACE( group_concat( distinct T1.ct_04, '</li><li>' ), ',', '' )
                    ,    '</li></ul></li>'
                )
            ,    '</li><li></li></ul></li>'
            ,    '</li></ul></li>'
        )as html_data
from    products_table T1
where    T1.hs_id >= 1001
    AND    T1.hs_id <= 1999
GROUP BY T1.ct_03
ORDER BY T1.ct_03
;
  • 抽出結果(html_data)
    '<li>A<ul><li>AA</li><li>BB</li><li>CC</li></ul></li>'
    '<li>B<ul><li>BB</li><li>CC</li></ul></li>'

※上記の抽出SQLではct_04が思うようにソートされない場合があります。
その方法を記載しなかったのは、本当にオススメできないから記載しなかっただけですので、
どーしてもこのやり方を選ばれる場合には、
ご自身で上記SQLを理解してct_04をソートして抽出するSQLにしてみてください。
(実際に導入しないにしても、SQLの理解とソートを追加した場合のSQLを考えるのは良い事だと思います)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/31 00:53

    tomari_perform さん
    sqlでここまで出来るんですね!びっくりです。
    この方法が上手に使えたらバッチリです。

    実はここはまだ中間地点で、この先もう少し難しい事がまっています。
    教えていただいた方法をうまく使って進めてみます

    また行き詰まったらよろしくお願い致します。ありがとうございます。
    感謝。感謝。

    キャンセル

+1

Schema

CREATE TABLE `category` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `parent_id` int(10) unsigned DEFAULT NULL,
  `category_name` varchar(128) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

Program

<?php
ini_set('display_errors', true);
error_reporting(E_ALL);

function h($string)
{
    return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

$dsn = 'mysql:host=localhost;dbname=test;charset=utf8;';
$username = 'root';
$password = 'password';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];

$pdo = new PDO($dsn, $username, $password, $options);

$sql = 'SELECT ';
$sql .= 'id, ifnull(parent_id, 0) as parent_id, category_name ';
$sql .= 'FROM category ';
$sql .= 'ORDER BY parent_id';
$stmt = $pdo->prepare($sql);
$stmt->execute();
$categories = $stmt->fetchAll();

$category_group = [];
foreach ($categories as $category) {
    $category_group[$category['parent_id']][] = $category;
}
?>
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div>
            <ul>
                <?php foreach ($category_group[0] as $category): ?>
                    <li><?= h($category['category_name']); ?></li>
                    <?php if (isset($category_group[$category['id']])): ?>
                        <ul>
                            <?php foreach ($category_group[$category['id']] as $cat) : ?>
                                <li><?= h($cat['category_name']); ?></li>
                            <?php endforeach; ?>
                        </ul>
                    <?php endif; ?>
                <?php endforeach; ?>
            </ul>
        </div>
    </body>
</html>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/30 08:22

    Kosuke_Shibuya さん
    コーディングしてくださり、ありがとうございます。
    なんとなくわかるような気がします。まだまだ初心者なものでひとつひとつ理解してみます。

    キャンセル

+1

カテゴリのマスターテーブル作ってそこから取得するのが手っ取り早いと思うけど。
商品に割り当てられていないカテゴリは表示したくないなら、

select distinct ct_03, ct_04 from table orderby ct_03, ct_04

でct_03, ct_04の組み合わせの重複を除去したものを取得

for ループで ct_03の値が変わったらct_04のリストを作り直す

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/30 08:48

    Tak1016 さん
    回答ありがとうございます。
    distinct ってあるんですね、知りませんでした
    これをどう使用すればよいか悩んでみます

    キャンセル

  • 2017/07/30 20:55

    Tak1016 さん
    考えてみたんですが
    ーーーー
    でct_03, ct_04の組み合わせの重複を除去したものを取得
    for ループで ct_03の値が変わったらct_04のリストを作り直す
    ーーーー
    が思いつきません、初心者ですみません
    具体的にどう書けばよいかヒントをください

    よろしくお願い致します。

    キャンセル

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

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • PHPに関する質問
  • mysql に登録した商品マスターのカテゴリー名をPHPでリストメニューを作りたい。(難易度5)