Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

MySQLで履歴テーブルの最新を取りたい(Group ByとOrder By)

よくありますよね。履歴テーブルの最新を取りたいってやつ。履歴テーブルを顧客で集計して、その最新の履歴をゲットしたい。こういうやつだ。

select
 id,
 user_id,
 access_path,
 created
from
 logs
where
  year(created) = 2015
group by
  user_id
order by
  id desc

logsテーブルをuser_idで集計してまとめ上げ、その中の最新のレコードをorder byで習得する。が、このSQLは全く機能しません。MySQLだけなのか、他のDBMSでも機能しないのかはわかりませんが、手元のMySQL5.6系ではgroup byされた段階で「最も古い」idが取得された。最古のレコードの値が入るみたい。

SQLで頑張る

本件を解決するには、こういうSQLを発行します。FROM句を予め絞って取得して最新の順番で並べておいて、そこからgroup byすると集計される。

select
*
from
(
select
 id,
 user_id,
 access_path,
 created
from
 logs
where
  year(created) = 2015
order by
  id desc
) as tmp_table group by user_id

SQLで頑張らない

SQLで頑張らない場合は、group byを諦める。とりあえず最新の順番でレコードを取ってきて、プログラムでgroup byする。

リストをuser_idでgroupbyすると、user_idがキーとなるリストに分割される。それをループして更に最新のレコードのみを抽出すると、欲しかったuser_id毎の最新のレコードの一覧表を生成することが出来ます。

Pythonにはリスト操作でgroupbyっていう関数がある。こんな感じで使います。

# sampleにはSQLでソート済の配列が入っている前提です
import itertools
group_bys = itertools.groupby(sample, key=lambda x: x.user_id)
group_by_list = []
  for key,main in group_by_unit_prices:
    for sub in main:
      # 最初の要素=最新のレコード
      # appendしたら内側のループは終わり
      group_by_list.append(sub)
      break

SQLを学習できるWebサービスを作りました。

www.start-sql.net