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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

3回答

1169閲覧

MySQL 前週比をだしたい。

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

1クリップ

投稿2017/07/03 09:38

###前提・実現したいこと
先日似たような質問をさせていただいたのですが、その応用的なことができるのかなーと思い自分で試してみたのですがなかなか上手くいかないので質問させていただきます。

以下のようなことができないか模索中です

前週とのコスト比率を算出。
自己結合にて解ける?

カラムとしては下記を含めたい

該当週の先頭日付(日曜日の日付) → ソート順1番目
チーム名 → ソート順2番目
該当週のコスト
前週のコスト
該当週と前週との割合を百分率表記(パーセント、小数点以下二桁で四捨五入)

というような感じでできないのかなと考えています

現在あるテーブルは以下の通りです。おそらく使用するであろうテーブルだけ書いておきます

teamテーブル

teamiDteam_nam
1aaa
2bbb
3ccc
4ddd
5eee

各メンバーの日給
daily_salaryテーブル

member_idpay
1100000
2200000
3300000
:

メンバーがどこのチームに所属しているか
team_memberテーブル

member_idteam_id
13
22
31
::

各メンバーが1日何時間働いたか
time_sheetsテーブル

member_idwork_dayworking_hours
12015-06-018
12015-06-028
12015-06-038
:::
22015-06-018
22015-06-028
22015-06-038
:::

このほかにメンバーidやメンバーの名前のレコードがあるmemberテーブルがあります
###該当のソースコード
前回の質問の時に以下のようなコードを書きました

SELECT DATE_SUB(work_day, INTERVAL (WEEKDAY(work_day) + 1) DAY) AS 該当週の先頭日付, team.name AS team_name, sum(time_sheets.working_hours * daily_salary.pay / 8) AS 当週コスト, FROM time_sheets INNER JOIN daily_salary ON time_sheets.member_id = daily_salary.member_id INNER JOIN team_member ON time_sheets.member_id = team_member.member_id INNER JOIN team ON team_member.team_id = team.team_id WHERE time_sheets.work_day BETWEEN '2015-06-01' AND '2015-06-30' GROUP BY 該当週の先頭日付,team.team_id; +--------------------------+-----------+---------------+ | 該当週の先頭日付 | team_name | コスト | +--------------------------+-----------+---------------+ | 2015-05-31 | Alfa | 5825000.0000 | | 2015-05-31 | Bravo | 10637500.0000 | | 2015-05-31 | Charlie | 8025000.0000 | | 2015-05-31 | Delta | 8550000.0000 | | 2015-05-31 | Echo | 11762500.0000 | | 2015-05-31 | Golf | 17612500.0000 | | 2015-06-07 | Alfa | 5775000.0000 | | 2015-06-07 | Bravo | 10400000.0000 | | 2015-06-07 | Charlie | 8350000.0000 | | 2015-06-07 | Delta | 8600000.0000 | | 2015-06-07 | Echo | 12612500.0000 | | 2015-06-07 | Golf | 18262500.0000 | | 2015-06-14 | Alfa | 5462500.0000 | | 2015-06-14 | Bravo | 10387500.0000 | | 2015-06-14 | Charlie | 7925000.0000 | | 2015-06-14 | Delta | 8437500.0000 | | 2015-06-14 | Echo | 10975000.0000 | | 2015-06-14 | Golf | 17875000.0000 | | 2015-06-21 | Alfa | 5275000.0000 | | 2015-06-21 | Bravo | 10125000.0000 | | 2015-06-21 | Charlie | 8300000.0000 | | 2015-06-21 | Delta | 8800000.0000 | | 2015-06-21 | Echo | 12887500.0000 | | 2015-06-21 | Golf | 16875000.0000 | | 2015-06-28 | Alfa | 2650000.0000 | | 2015-06-28 | Bravo | 3912500.0000 | | 2015-06-28 | Charlie | 3075000.0000 | | 2015-06-28 | Delta | 3225000.0000 | | 2015-06-28 | Echo | 4812500.0000 | | 2015-06-28 | Golf | 7362500.0000 | +--------------------------+-----------+---------------+

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2017/07/03 14:10

「CREATE文を提示してくれれば、環境作って回答するけど、文字起こしまではしたくない。」←回答者の本音
退会済みユーザー

退会済みユーザー

2017/07/03 23:59

なるほど!確かにそうですね。指摘ありがとうございます。修正します。
guest

回答3

0

週ごとに集計したVIEWをつくって、1週ずらして結合するのが妥当です。
ただし特定の週に1件もデータがないときは何週も遡るのか?
それとも0とみなして結合するのかによって処理がかわってきます

投稿2017/07/03 09:55

yambejp

総合スコア114843

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

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

退会済みユーザー

退会済みユーザー

2017/07/03 23:41

ありがとうございます!参考にさせていただきます!
guest

0

サブクエリを使わない事にこだわっているのは、性能面ですかね?
たいした件数がなければ、そこまで気にせず、
できる方法で作ってしまった方が良い気もしますが。

あと、teamiDとteam_idがあったので、team_idに統一して、以下、回答です。
結局サブクエリですが、性能面は問題ないかと。

SQL

1create table if not exists tmp_date( 2 now_week_start date NOT NULL 3 , now_week_end date NOT NULL 4 , last_week_start date NOT NULL 5 , last_week_end date NOT NULL 6 , PRIMARY KEY( now_week_start ) 7)ENGINE=InnoDB DEFAULT CHARSET='utf8'; 8 9INSERT INTO tmp_date values 10 ( '2015-06-08', '2015-06-14', '2015-06-01', '2015-06-07' ) 11,( '2015-06-15', '2015-06-22', '2015-06-08', '2015-06-14' ) 12; -- 好きなだけ増やしてください。

SQL

1SELECT T0.now_week_start as week 2 , T1.team_name 3 , ( 4 SELECT sum( T3.working_hours * T4.pay / 8) AS now_week_cost 5 FROM team_member T2 6 LEFT JOIN time_sheets T3 ON( 7 T3.member_id = T2.member_id 8 ) 9 LEFT JOIN daily_salary T4 ON( 10 T4.member_id = T3.member_id 11 ) 12 WHERE T2.team_id = T1.team_id 13 AND T3.work_day BETWEEN T0.now_week_start 14 AND T0.now_week_end 15 GROUP BY T2.team_id 16 ) as now_week_cost 17 , ( 18 SELECT sum( T3.working_hours * T4.pay / 8) AS last_week_cost 19 FROM team_member T2 20 LEFT JOIN time_sheets T3 ON( 21 T3.member_id = T2.member_id 22 ) 23 LEFT JOIN daily_salary T4 ON( 24 T4.member_id = T3.member_id 25 ) 26 WHERE T2.team_id = T1.team_id 27 AND T3.work_day BETWEEN T0.last_week_start 28 AND T0.last_week_end 29 GROUP BY T2.team_id 30 ) as last_week_cost 31 , round( 32 ( 33 SELECT sum( T3.working_hours * T4.pay / 8) AS now_week_cost 34 FROM team_member T2 35 LEFT JOIN time_sheets T3 ON( 36 T3.member_id = T2.member_id 37 ) 38 LEFT JOIN daily_salary T4 ON( 39 T4.member_id = T3.member_id 40 ) 41 WHERE T2.team_id = T1.team_id 42 AND T3.work_day BETWEEN T0.now_week_start 43 AND T0.now_week_end 44 GROUP BY T2.team_id 45 ) 46 / ifnull( 47 ( 48 SELECT sum( T3.working_hours * T4.pay / 8) AS last_week_cost 49 FROM team_member T2 50 LEFT JOIN time_sheets T3 ON( 51 T3.member_id = T2.member_id 52 ) 53 LEFT JOIN daily_salary T4 ON( 54 T4.member_id = T3.member_id 55 ) 56 WHERE T2.team_id = T1.team_id 57 AND T3.work_day BETWEEN T0.last_week_start 58 AND T0.last_week_end 59 GROUP BY T2.team_id 60 ) 61 , 9999999999 ) -- 適当に0処理。 62 * 100 63 , 2 64 ) as cost_perform -- サブクエリでの算出の方が理想。 65FROM tmp_date T0 66 , team T1 67ORDER BY T0.now_week_start, T1.team_name

投稿2017/07/04 02:04

tomari_perform

総合スコア760

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

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

退会済みユーザー

退会済みユーザー

2017/07/04 02:16

ありがとうございます! teamiDのところ記入ミスでした。
guest

0

ベストアンサー

合計を二つ繋げてみました。

sql

1SELECT t1.sweek, t1.team_name, round(COALESCE(t2.cost,0)/t1.cost*100,2) pcost FROM 2( 3SELECT 4 DATE_SUB(work_day, INTERVAL (WEEKDAY(work_day) + 1) DAY) AS sweek, 5 team.name AS team_name, 6 sum(time_sheets.working_hours * daily_salary.pay / 8) AS cost, 7 DATE_SUB(work_day, INTERVAL (WEEKDAY(work_day) + 1 + 7) DAY) lweek 8FROM 9 time_sheets 10INNER JOIN 11 daily_salary 12ON 13 time_sheets.member_id = daily_salary.member_id 14INNER JOIN 15 team_member 16ON 17 time_sheets.member_id = team_member.member_id 18INNER JOIN 19 team 20ON 21 team_member.team_id = team.team_id 22WHERE 23 time_sheets.work_day 24 BETWEEN 25 '2015-06-01' 26 AND 27 '2015-06-30' 28GROUP BY 29 sweek,team.team_id 30) t1 31LEFT JOIN 32( 33SELECT 34 DATE_SUB(work_day, INTERVAL (WEEKDAY(work_day) + 1) DAY) AS sweek, 35 team.name AS team_name, 36 sum(time_sheets.working_hours * daily_salary.pay / 8) AS cost 37FROM 38 time_sheets 39INNER JOIN 40 daily_salary 41ON 42 time_sheets.member_id = daily_salary.member_id 43INNER JOIN 44 team_member 45ON 46 time_sheets.member_id = team_member.member_id 47INNER JOIN 48 team 49ON 50 team_member.team_id = team.team_id 51WHERE 52 time_sheets.work_day 53 BETWEEN 54 '2015-05-01' 55 AND 56 '2015-06-30' 57GROUP BY 58 sweek,team.team_id 59) t2 ON t2.sweek = t1.lweek AND t1.team_name=t2.team_name 60ORDER BY t1.sweek, t1.team_name 61;

SUBクエリしないのも作ってみました

sql

1SELECT 2 DATE_SUB(t1.work_day, INTERVAL (WEEKDAY(t1.work_day) + 1) DAY) AS sweek, 3 team.name AS team_name, 4 round(COALESCE(sum(t2.working_hours * daily_salary.pay / 8),0) / sum(t1.working_hours * daily_salary.pay / 8) * 100,2) AS pcost 5FROM 6 time_sheets t1 7INNER JOIN 8 daily_salary 9ON 10 t1.member_id = daily_salary.member_id 11INNER JOIN 12 team_member 13ON 14 t1.member_id = team_member.member_id 15INNER JOIN 16 team 17ON 18 team_member.team_id = team.team_id 19LEFT JOIN 20 time_sheets t2 ON DATE_SUB(t1.work_day, INTERVAL (WEEKDAY(t1.work_day) + 1 + 7) DAY)=DATE_SUB(t2.work_day, INTERVAL (WEEKDAY(t2.work_day) + 1) DAY) 21 AND t1.member_id=t2.member_id 22WHERE 23 t1.work_day 24 BETWEEN 25 '2015-06-01' 26 AND 27 '2015-06-30' 28GROUP BY 29 sweek,team.team_id

投稿2017/07/03 23:41

編集2017/07/04 01:36
A.Ichi

総合スコア4070

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

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

退会済みユーザー

退会済みユーザー

2017/07/03 23:58

ありがとうございます! これはサブクエリですか?
A.Ichi

2017/07/04 00:04

そうですね。2階層のクエリですね。 t1とt2のLEFT JOINがサブクエリになるんでしょうね。
退会済みユーザー

退会済みユーザー

2017/07/04 00:35

回答ありがとうございます! サブクエリでの方法参考にさせていただきます! どうやらサブクエリを使わないでもできるらしいので引き続き模索していきます。
tomari_perform

2017/07/04 01:58

1つ目のクエリで良いと思うんですけどね。 2つ目のクエリは、出勤しない日もworking_hoursが0で行が存在する事が前提になりますね。
退会済みユーザー

退会済みユーザー

2017/07/04 02:18

なるほど。そうなんですね。 説明ありがとうございます。参考にさせていただきます。
A.Ichi

2017/07/04 02:24

出社された人は最低1時間は、働きましょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問