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

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

ただいまの
回答率

87.59%

3つのテーブルをGROUP_CONCATでまとめたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,405

score 403

2つまでならできますが3つになるとできません...

①まずnameテーブルを基準にskillテーブルだけ結合します。
SELECT * FROM name 
LEFET JOIN skill;
イメージ説明

②次にリレーション張ります。
SELECT * FROM name LEFT JOIN skill ON name.id=skill.user_id;
イメージ説明

③次に表示するカラム名を指定しておきます。
SELECT name.id, name, 
skill.id, skill.user_id, skill,level 
FROM name 
LEFT JOIN skill ON name.id=skill.user_id;
イメージ説明

④GROUP BYでまとめます。
SELECT name.id, name, 
skill.id, skill.user_id, skill, level 
FROM name 
LEFT JOIN skill ON name.id=skill.user_id 
GROUP BY name.id;
イメージ説明

⑤skillが1つしか表示されないのでgroup_concatでまとめます。
SELECT name.id, name, 
skill.id, skill.user_id, GROUP_CONCAT(skill), GROUP_CONCAT(level) 
FROM name 
LEFT JOIN skill ON name.id=skill.user_id 
GROUP BY name.id;
イメージ説明

⑥更にitemテーブルも追加させたくなりました。
SELECT name.id, name, 
skill.id, skill.user_id, GROUP_CONCAT(skill), GROUP_CONCAT(level) 
FROM name 
LEFT JOIN skill ON name.id=skill.user_id 
LEFT JOIN item ON name.id=item.user_id 
GROUP BY name.id;
イメージ説明

⑦表示がずれてしまったので⑤に戻りますが、
テーブルはname+itemにしてみます。
SELECT name.id, name, 
item.id, item.user_id, GROUP_CONCAT(item), GROUP_CONCAT(num) 
FROM name 
LEFT JOIN item ON name.id=item.user_id 
GROUP BY name.id;
イメージ説明

2つのテーブルまでなら、まとめることができますが
⑤と⑦をまとめるにはどうしたらよろしいでしょうか?

⑧試しに下記を試してみました。
SELECT name.id, name, 
skill.id, skill.user_id, GROUP_CONCAT(skill), GROUP_CONCAT(level),
item.id, item.user_id, GROUP_CONCAT(item), GROUP_CONCAT(num)  
FROM name 
LEFT JOIN skill ON name.id=skill.user_id 
LEFT JOIN item ON name.id=item.user_id 
GROUP BY name.id
\G;

イメージ説明

同じskillが沢山入ってます。
あとからexplode()で配列を取得する予定なので、同じ名前はいらないのです。
ある分だけ欲しいので、最後の画像のもので言えばskillとlevelがある分だけ表示されてほしいのです。
それが必要なデータだからです。


例えば、こんな感じで使用したいのです。

$en = filter_input(INPUT_GET, 'EN');
$sql = "SELECT name.id, name AS 'キャラ名', 
GROUP_CONCAT(skill) AS '技',GROUP_CONCAT(level) AS 'レベル', 
GROUP_CONCAT(item) AS 'アイテム',GROUP_CONCAT(num) AS '個数' 
FROM name 
LEFT JOIN skill ON name.id = skill.user_id 
LEFT JOIN item ON name.id = skill.user_id 
WHERE name.id = '$en' GROUP BY name.id";

$stmt = $pdo->prepare($sql);
$stmt->execute();

var_dump($sql);



foreach ($stmt as $row) {
    echo '<br /><br />';
    echo 'キャラ名:'.$row['キャラ名'].'<br />';

    $skill =$row['技'];
    $skillArray = explode(",", $skill);

    $level =$row['レベル'];
    $levelArray = explode(",", $level);

    for($i = 0;$i < count($skillArray);$i++) {
        echo '<br />';
        echo '技名:'.$skillArray[$i].'<br />';
        echo 'レベル:'.$levelArray[$i].'<br />';
    }

    $item =$row['アイテム'];
    $itemArray = explode(",", $item);

    $num =$row['個数'];
    $numArray = explode(",", $num);

    for($i = 0;$i < count($itemArray);$i++) {
        echo '<br />';
        echo 'アイテム名:'.$itemArray[$i].' '.$levelArray[$i].'個<br />';
    }

}

echo '<br />';
print_r($skillArray);
echo '<br /><br />';
print_r($levelArray);
echo '<br /><br />';
print_r($itemArray);
echo '<br /><br />';
print_r($numArray);

↓結果(ここから)

キャラ名:ナルト

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

アイテム名:ポーション 15個

アイテム名:ポーション 15個

アイテム名:ハイポーション 20個

アイテム名:ハイポーション 20個

アイテム名:エリクサー 18個

アイテム名:エリクサー 18個

アイテム名:フェニックスの尾 36個

アイテム名:フェニックスの尾 36個

アイテム名:ポーション 52個

アイテム名:ポーション 52個

アイテム名:ハイポーション 21個

アイテム名:ハイポーション 21個

アイテム名:エリクサー 14個

アイテム名:エリクサー 14個

アイテム名:フェニックスの尾 55個

アイテム名:フェニックスの尾 55個

アイテム名:ラストエリクサー 22個

アイテム名:ラストエリクサー 22個

アイテム名:薬草 21個

アイテム名:薬草 21個

Array ( [0] => 螺旋丸 [1] => 螺旋手裏剣 [2] => 螺旋丸 [3] => 螺旋手裏剣 [4] => 螺旋丸 [5] => 螺旋手裏剣 [6] => 螺旋丸 [7] => 螺旋手裏剣 [8] => 螺旋丸 [9] => 螺旋手裏剣 [10] => 螺旋丸 [11] => 螺旋手裏剣 [12] => 螺旋丸 [13] => 螺旋手裏剣 [14] => 螺旋丸 [15] => 螺旋手裏剣 [16] => 螺旋丸 [17] => 螺旋手裏剣 [18] => 螺旋丸 [19] => 螺旋手裏剣 ) 

Array ( [0] => LV50 [1] => LV80 [2] => LV50 [3] => LV80 [4] => LV50 [5] => LV80 [6] => LV50 [7] => LV80 [8] => LV50 [9] => LV80 [10] => LV50 [11] => LV80 [12] => LV50 [13] => LV80 [14] => LV50 [15] => LV80 [16] => LV50 [17] => LV80 [18] => LV50 [19] => LV80 ) 

Array ( [0] => ポーション [1] => ポーション [2] => ハイポーション [3] => ハイポーション [4] => エリクサー [5] => エリクサー [6] => フェニックスの尾 [7] => フェニックスの尾 [8] => ポーション [9] => ポーション [10] => ハイポーション [11] => ハイポーション [12] => エリクサー [13] => エリクサー [14] => フェニックスの尾 [15] => フェニックスの尾 [16] => ラストエリクサー [17] => ラストエリクサー [18] => 薬草 [19] => 薬草 ) 

Array ( [0] => 15 [1] => 15 [2] => 20 [3] => 20 [4] => 18 [5] => 18 [6] => 36 [7] => 36 [8] => 52 [9] => 52 [10] => 21 [11] => 21 [12] => 14 [13] => 14 [14] => 55 [15] => 55 [16] => 22 [17] => 22 [18] => 21 [19] => 21 )

↑結果(ここまで)

本当はこう表示させたいのです。

キャラ名:ナルト

技名:螺旋丸
レベル:LV50

技名:螺旋手裏剣
レベル:LV80

アイテム名:ポーション 15個

アイテム名:ハイポーション 20個

アイテム名:エリクサー 18個

アイテム名:フェニックスの尾 36個

イメージ説明

user_id=2のしか持っていない薬草まで表示されてしまっているのでおかしいのです...

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • yambejp

    2016/06/27 14:36

    それぞれのtableの例示はcreate table形式で表示すると再現しやすい

    キャンセル

  • earnest_gay

    2016/06/27 15:06

    >>tableの例示はcreate table形式で表示

    どういうことでしょうか?

    キャンセル

回答 3

checkベストアンサー

0

クエリを横にずらっと並べて書くと非常にわかりづらいと思います。
LEFT JOIN をするのは結構ですが、何が欲しいのか目的がわかりづらいので、次のような感じで書いてみてはどうでしょうか。
テーブルに何があるのか読み取るのが大変だったので適当ですが…。

SELECT name.id, name, skills, levels FROM name
    LEFT JOIN (select GROUP_CONCAT(skill) AS skills group by user_id) SK ON name.id=SK.user_id
    LEFT JOIN (select GROUP_CONCAT(level) AS levels group by user_id) LV ON name.id=LV.user_id


クエリ自体は未検証です。間違ってたらすみません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/27 15:07

    読みづらくてすいません。
    修正追加させて頂きました。

    キャンセル

  • 2016/06/27 16:02 編集

    こちらの回答を待たずとも自力で試していただきたかったですが、先に書いてみました(未検証)
    select name.id, name, skills, levels, items, nums from name
    left join (select group_concat(skill) as skills, group_concat(level) as levels from skill group by user_id) SK on name.id=SK.user_id
    left join (select group_concat(item) as items, group_concat(num) as nums from item group by user_id) IT on name.id=IT.user_id
    これでうまくできれば、あとはPHP側でexplodeで分解するなどすればよいかと思います。

    キャンセル

  • 2016/06/27 18:07

    ありがとうございます!
    JOINの仕組みが理解できていない状態でJOINを多用しようとした結果
    余計に難しいことをしようとしていました。

    それぞれのSQL文にすることで解決しそうです。

    キャンセル

0

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/27 15:29

    うまくいきません...

    MariaDB [test]> SELECT DISTICT name.id, name AS 'キャラ名',
    -> GROUP_CONCAT(skill) AS '技',GROUP_CONCAT(level) AS 'レベル',
    -> GROUP_CONCAT(item) AS 'アイテム',GROUP_CONCAT(num) AS '個数'
    -> FROM name
    -> LEFT JOIN skill ON name.id = skill.user_id
    -> LEFT JOIN item ON name.id = skill.user_id
    -> WHERE name.id =1
    -> GROUP BY name.id
    -> \G;
    ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.id, name AS 'キャラ名',
    GROUP_CONCAT(skill) AS '技',GROUP_CONCAT(level) A' at line 1
    ERROR: No query specified

    キャンセル

  • 2016/06/27 15:31

    シンタックスエラーというのは単なる文法違反です。ルールに従って書き直してください。オレオレルールをごり押ししてもうまくいきません。

    キャンセル

  • 2016/06/27 17:10

    > Kosuke_Shibuya さん

    distict ではなく、distinct ではないでしょうか

    キャンセル

  • 2016/06/27 17:18

    attakeiさん
    スペルミスしてましたね。

    キャンセル

0

前回回答した通り

select name,group_concat(concat(`skill_name`,',',`level`) separator ';') as skill
from ・・・
group by name


が最も効率的なデータの取り出し方だと思います

PHP側で出てきたskillを「;」で分割後してforでまわしその中で
「,」で分割してul-liで表示してください

※ごめんなさい、転記ミスをなおしました

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/27 15:23

    知識不足で仰られていることがよくわからないのですが

    (`skill_name`,',',`level`) separator ';')

    の分部が分かりません...

    キャンセル

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

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る