QA@IT

Rails ActiveRecordでの増分の計算方法について。

3129 PV

環境
Ruby on Rails 3.2.9
Ruby 2.0.0
SQLite3

一時間ごとの行同士の増分の計算を行う方法がわからず困っています。
表現しにくいのですが下記のような処理を行いたいと考えています。

テーブル名:genreps
+-------------------------------+ +-------------------------------+
created_at         kilowatthour
+-------------------------------+ +-------------------------------+
2013/04/12 08:00:00    0.0
2013/04/12 09:00:00    2.0
2013/04/12 10:00:00    3.5
2013/04/12 11:00:00    4.7


+-------------------------------+ +-------------------------------+
created_at         kilowatthour(zoubun)
+-------------------------------+ +-------------------------------+
2013/04/12 08:00:00    2.0
2013/04/12 09:00:00    1.5
2013/04/12 10:00:00    1.2

のように集計したいのですがなにか方法はありますでしょうか。
SQLiteでは不可能な場合はMySQLでも構いません。

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

回答

未完成で申し訳ないのですが、

SELECT
  a.created_at,
  b.created_at,
  b.kilowatthour - a.kilowatthour AS zoubun
FROM genreps AS a
JOIN genreps AS b
WHERE a.created_at < b.created_at;

2013-04-12 08:00:00.000000  2013-04-12 09:00:00.000000  2
2013-04-12 08:00:00.000000  2013-04-12 10:00:00.000000  3.5
2013-04-12 08:00:00.000000  2013-04-12 11:00:00.000000  4.7
2013-04-12 09:00:00.000000  2013-04-12 10:00:00.000000  1.5
2013-04-12 09:00:00.000000  2013-04-12 11:00:00.000000  2.7
2013-04-12 10:00:00.000000  2013-04-12 11:00:00.000000  1.2

まではたどり着けるので、あとは同じ a.created_at のレコード中 b.created_at が最小のものを取り出せばよいはずですが…

副問い合わせで NOT EXISTS を使うとうまく書けたような…

編集 履歴 (0)

MySQL限定でちょっとトリッキーですが、次のようなクエリを発行すればできると思います。
ActiveRecord で行う方法はわかりません。

mysql> set @k=0;
mysql> select created_at,kilowatthour-@k,@k:=kilowatthour from genreps order by created_at;
+---------------------+-----------------+------------------+
| created_at          | kilowatthour-@k | @k:=kilowatthour |
+---------------------+-----------------+------------------+
| 2013-04-12 08:00:00 |             0.0 |              0.0 |
| 2013-04-12 09:00:00 |             2.0 |              2.0 |
| 2013-04-12 10:00:00 |             1.5 |              3.5 |
| 2013-04-12 11:00:00 |             1.2 |              4.7 |
+---------------------+-----------------+------------------+
編集 履歴 (0)

時間がきっかり1時間おきであるなら、もう1つの自テーブルを、時刻を1時間ずらしてJOINすることによって求めることが出来ます。

SELECT
    a.created_at,
    b.kilowatthour - a.kilowatthour AS 'kilowatthour(zoubun)'
  FROM genreps AS a
  JOIN genreps AS b
    ON datetime(a.created_at, '+1 hour')
       = datetime(b.created_at, '+0 hour');
2013-04-12 08:00:00.000000  2
2013-04-12 09:00:00.000000  1.5
2013-04-12 10:00:00.000000  1.2

私だったら、これくらいの込み入り具合だったら、無理にARの形に落とし込むよりSQLを execute してしまうかなー。

編集 履歴 (0)
  • JOINよりSELECT内で副問合せしたほうがいいんじゃに?この手のテーブルは結合するとボトルネックになりがち -
  • すみません。きっかり1時間でない場合の方法も教えていただけないでしょうか。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。