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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

2回答

275閲覧

3つのテーブルを使った対応表をCSV出力する方法がわからない

waiemu

総合スコア14

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

0クリップ

投稿2019/01/10 02:29

編集2019/01/10 09:58

前提・実現したいこと

  • PHP7.2
  • Laravel5.6
  • MySQL5.6

イベント出欠確認システムを作成しております。
ユーザーごとのイベント毎の出欠を確認するCSV出力する機能の作成途中に行き詰っています。
どうぞよろしくお願いいたします。

usersテーブル

idnameage
1一郎30
2次郎29
3三郎28
4四子27
5五子26
6六子25

eventsテーブル

idnamedate
1第1回イベント2018-01-01
2第2回イベント2018-02-01
3第3回イベント2018-03-01

event_userテーブル

iduser_idevent_idattendance
111出席
231出席
351欠席
412出席
552出席
662欠席
756出席
816出席
943出席
1065欠席

※event_userテーブルのuser_id,event_id はそれぞれテーブルIDと外部キー接続しています。

CSV出力イメージ
|||第1回イベント|第2回イベント|第3回イベント|第4回イベント|第5回イベント|第6回イベント|
|:--:|:--:|:--:|:--:|
|ユーザー名|年齢|出欠状態|出欠状態|出欠状態|出欠状態|出欠状態|出欠状態|
|一郎|30|出席|出席||||出席
|次郎|29||||||
|三郎|28|出席|||||
|四子|27|||出席|||
|五子|26|欠席|出席||||出席
|六子|25||欠席|||欠席|

データ取得の方法が思いつかず、詰まっています。

・データがない座標(例えば次郎はどのイベントにも参加していない)も含めて、NULLで出力したい
・各ユーザー、各イベントの出欠状態が一覧で見れる形であれば現在のイメージ図にはこだわらない

該当のソースコード

app/UserController.php

/* ユーザーごとの出欠・領収履歴 CSVダウンロード機能*/ public function csvAttendanceListDownload(Event $event, User $user, EventUser $eventuser) { $current = Carbon::now(); $formats = array(); #ファイル名の指定 $file_name = 'event_user_' . date('YmdHis') . '.csv'; $file_path = 'temp/' . $file_name; #ファイルの生成 $file = new \SplFileObject($file_path, 'w'); if ($file === false) { throw new Exception('ファイルの書き込みに失敗しました。'); } #出力する項目 //ユーザーデータ $query_select_users = ['users.*', 'event_user.id as event_user_id', 'event_user.user_id as event_user_user_id', 'event_user.event_id as event_user_event_id', 'event_user.attendance_status']; //イベントに対応したユーザーの出欠・領収情報の表示 $query_select_event_user = ['event_user.*', 'users.id as userId', 'events.id as eventId']; #取得データの生成 //イベント情報 $events = Event::get(); $count = count($events); //ユーザー情報 $download_users = User::select($query_select_users) ->leftJoin('event_user', function ($join_user) { $join_user->on('users.id', '=', 'event_user.user_id'); }) ->get(); //ユーザー毎とイベント毎の出欠状態 $download_event_users = Event::select($query_select_event_user) ->leftJoin('event_user', function ($join_event_user) { $join_event_user->on('events.id', '=', 'event_user.event_id'); }) ->rightJoin('users', function ($join_event_user) { $join_event_user->on('users.id', '=', 'event_user.user_id'); }) ->get(); #各行列の配置 //1行目は必要なイベント名を出力 $column_name_1 = array('', ''); //2行目は各データとイベントのカウント数「出欠状態」項目の表示 $column_name_2 = array('ユーザー名', '年齢'); // foreach($download_events as $download_event=> $val) { $column_name_1[] = $add_event_name; } mb_convert_variables('SJIS-win', 'UTF-8', $column_name_1); $file->fputcsv($column_name_1); $i = 0; while ($i < $count) { $add = '出欠'; $column_name_2[] = $add; $i++; } mb_convert_variables('SJIS-win', 'UTF-8', $column_name_2); $file->fputcsv($column_name_2); #データの出力 foreach ($download_users as $download_user => $user) { #文字コード変換と整形 $formats = array( array( mb_convert_encoding($user->name, 'SJIS-win', 'UTF-8'),//ユーザー名 mb_convert_encoding($user->age, 'SJIS-win', 'UTF-8'),//年齢 ) ); foreach ($formats as $format => $value) { $file->fputcsv($value); }; } #出欠状態 foreach ($download_event_users as $download_event_user => $event_user) { $add_attendance_status = mb_convert_encoding($event_user->attendance, 'SJIS-win', 'UTF-8');//出欠状態 //出欠状態 CSVへ追記 foreach ($formats as $format => $value) { $value[] = $add_attendance_status; $file->fputcsv($value); } } #ファイルの情報 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $file_name . '"'); header('Content-Length: ' . filesize($file_path)); readfile($file_path); return response()->download($file_path); }

試したこと

現状は、event_userに登録されているユーザーデータがすべて出力され、座標など関係なく、出欠状態データが出力されています。
何か参考になりそうなサイトなどご紹介いただければ幸いです。

何卒よろしくお願いいたします。

データイメージ

ユーザー名年齢(event_id)(attendance)
一郎301,2,,,,6出席,出席,,,,出席
次郎29,,,,,,,,,,
三郎281,,,,,出席,,,,,
四子27,,3,,,,,出席,,,
五子261,2,,,5,欠席,出席,,,出席
六子25,2,,,5,,欠席,,,欠席,

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

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

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

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

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

guest

回答2

0

ベストアンサー

CSVに関してはとりあえず置いておきます

  • 元データ

SQL

1create table users(uid int primary key,uname varchar(20),age int); 2create table events(eid int primary key,ename varchar(20),`date` date); 3create table event_user(euid int primary key,uid int not null,eid int not null,attendance set('出席','欠席'),unique key(uid,eid)); 4 5insert into users values 6(1,'一郎',30), 7(2,'次郎',29), 8(3,'三郎',28), 9(4,'四子',27), 10(5,'五子',26), 11(6,'六子',25); 12 13insert into events values 14(1,'第1回イベント','2018-01-01'), 15(2,'第2回イベント','2018-02-01'), 16(3,'第3回イベント','2018-03-01'), 17(4,'第4回イベント','2018-04-01'), 18(5,'第5回イベント','2018-05-01'), 19(6,'第6回イベント','2018-06-01'); 20 21insert into event_user values 22(1,1,1,'出席'), 23(2,3,1,'出席'), 24(3,5,1,'欠席'), 25(4,1,2,'出席'), 26(5,5,2,'出席'), 27(6,6,2,'欠席'), 28(7,5,6,'出席'), 29(8,1,6,'出席'), 30(9,4,3,'出席'), 31(10,6,5,'欠席'); 32
  • 集計

SQL

1select '' as uname,'' as age 2,group_concat(case eid when 1 then ename else '' end separator '') as ev1 3,group_concat(case eid when 2 then ename else '' end separator '') as ev2 4,group_concat(case eid when 3 then ename else '' end separator '') as ev3 5,group_concat(case eid when 4 then ename else '' end separator '') as ev4 6,group_concat(case eid when 5 then ename else '' end separator '') as ev5 7,group_concat(case eid when 6 then ename else '' end separator '') as ev6 8from events 9group by uname 10union all 11select 'ユーザー名','年齢','出欠状態','出欠状態','出欠状態','出欠状態','出欠状態','出欠状態' 12union all 13select uname,age 14,group_concat(case eid when 1 then attendance else '' end separator '') as ev1 15,group_concat(case eid when 2 then attendance else '' end separator '') as ev2 16,group_concat(case eid when 3 then attendance else '' end separator '') as ev3 17,group_concat(case eid when 4 then attendance else '' end separator '') as ev4 18,group_concat(case eid when 5 then attendance else '' end separator '') as ev5 19,group_concat(case eid when 6 then attendance else '' end separator '') as ev6 20from users as t1 21inner join event_user as t2 using(uid) 22group by uid; 23

投稿2019/01/10 03:11

yambejp

総合スコア114769

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

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

waiemu

2019/01/10 10:07

早速のご回答をありがとうございます。 group_concat については使用したことのない関数でしたので、今使い方を調べながら進めさせていただいております。 アドバイスいただいたことを自分なりに解釈してみたのですが、追加した「データイメージ」で間違いありませんでしょうか? もし、誤っているなど、ご指摘ありましたら、またコメントいただければ幸いです。
yambejp

2019/01/10 10:23

> データイメージ いや、むしろ私がつけたサンプルが命題にある「CSV出力イメージ」と同等なのですが そのまま実行して確認してもらえませんか?
waiemu

2019/01/11 10:35

SQL文を実行したところ、イメージ通りのデータが取得できました。 ご指摘ありがとうございます。 ただ、2つ目のクエリ文ですが、次郎(event_userにuidが無いユーザー)も含めてデータ取得することと、(これはinner joinではなく、left joinで解決?) eid の数と番号は、変動するので、データ取得するイベントIDを参照しながら、イベント数だけ「出欠状況」のカラムを追加するコードが必要でした。 この部分がLaravelのクエリビルダを使いながら実行できるか試してみたいと思います。 ありがとうございます。
yambejp

2019/01/11 11:00

イベントの数だけ全通り自動的に処理するならSQL側でやるなら procedureで解決してください php側でやっても構わないなら先行してイベント一覧を取得して sql文をプログラムで構築します
guest

0

yambejp様 ありがとうございました。
遅くなりましたが、ようやく完成しました。
思った通りのデータができました。

app/UserController.php

public function csvAttendanceListDownload(Event $event, User $user, EventUser $eventuser) { /*ファイル名の指定 パスの指定*/ $file_name = 'event_user_' . date('YmdHis') . '.csv'; $file_path = 'temp/' . $file_name; /*ファイルの生成 $file = new \SplFileObject($file_path, 'w'); if ($file === false) { throw new Exception('ファイルの書き込みに失敗しました。'); } //イベントデータ $download_events = Event::get(); $event_count = count($download_events);//イベントの数 //1行目はカウントが必要なイベント名を出力 $column_name_1 = ['', ''];//名前と年齢の列を空けておく foreach ($download_events as $download_event) { $column_name_1[] = $download_event->name; } mb_convert_variables('SJIS-win', 'UTF-8', $column_name_1); $file->fputcsv($column_name_1); //2行目は各データと出力するイベント分の数だけ「出欠状態」項目の表示 $i = 0; $column_name_2 = array('名前', '年齢'); while ($i < $event_count) { $add_attend_column = '出欠'; $column_name_2[] = $add_attend_column; $i++; } mb_convert_variables('SJIS-win', 'UTF-8', $column_name_2); $file->fputcsv($column_name_2); $eventusers = EventUser::get(); $select_user_data = ['users.name', 'users.age', ]; $bindings = []; /*テーブル出力準備*/ foreach ($download_events as $download_event) { $select_user_data[] = (DB::raw( "MAX(CASE WHEN event_user.event_id = ? THEN event_user.attendance_status ELSE NULL END) AS attendance_" . $int )); $bindings[] = $download_event->id; $int++; } $download_users = User::select($select_user_data) ->addBinding($bindings, 'select')//addBindingで「?」の指定 ->leftJoin('event_user', 'users.id', '=', 'event_user.user_id') ->groupBy('users.id')//database,php --strictをfalseにしなければならな ->get() ; /*文字コード変換と整形*/ $formats = []; foreach ($download_users as $download_user) { $formats_row = array( mb_convert_encoding($download_user->name, 'SJIS-win', 'UTF-8'),//名前 mb_convert_encoding($download_user->age, 'SJIS-win', 'UTF-8'),//年齢 //イベントの数だけ出欠状態を追加 for($i = 0; $i < $event_count; $i++) { $formats_row[] = mb_convert_encoding $download_user->{'attendance_'.$i}), 'SJIS-win', 'UTF-8');//出欠状態 } $formats[] = $formats_row; } foreach ($formats as $val) { $file->fputcsv($val); } //ファイルの情報 header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . $file_name . '"'); header('Content-Length: ' . filesize($file_path)); readfile($file_path); return response()->download($file_path); }

投稿2019/01/21 07:14

waiemu

総合スコア14

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問