QA@IT

複数のテーブルから、共通のカラムを基準にデータを取得したい

4869 PV

Railsで複数のテーブルから共通のカラムを基準にデータを取得しようとしているのですが、やり方がわからず質問させていただきました。
Railsは4、DBはsqliteを使っています。

具体的に説明させていただきます。

健在、ゲームの履歴をDBに入れて管理しようとしています。

例えば、
ユーザが何時にアイテムを手に入れた。
ユーザが何時にモンスターを倒した。
等です。
ここで全ての履歴に共通な事柄は、ユーザが何時に○○したというように、ユーザとそのイベントの時間という2つの事柄は必ず含みます。

この履歴を保存を実現する為に私は、

GetItemHistory id,user_id,action_time,item_id
AttackHistory  id,user_id,action_time,monster_id
User       id,name

というテーブルとカラムを作成しました。

ここで私は、最近のデータ50件を取りたいと考えました。
そこでaction_timeをorderにいれて、selectしようとしたのですが、やり方がわかりません。

テーブルの構造が間違っている等でも構いません。
ご回答いただけると助かります。

回答

なにをselectの結果として残せていれば日本語化できるかわからなかったのでそのあたり適当ですが、
テーブルが分かれたままとして、unionを使う場合。

select * from
  (select user_id,action_time,item_id id,1 kind from GetItemHistory
     order by action_time desc limit 50)

union all

select * from 
  (select user_id,action_time,monster_id id,2 kind from AttackHistory
     order by action_time desc limit 50)

order by action_time desc limit 50

全部にlimit句がついているのは、履歴テーブルですとそこそこの件数になりそうですので、
unionの前に50件にしておくほうが作業域節約になるかなーと思ったまでです。
パフォーマンスにどの程度影響がでるかはインデックスにも左右されると思いますが、
一例として。

あと、結合後にどちらのテーブルだったかわかるようにkind列を追加してます。
上の例だと、kindが1だと、idはitem_idです。kindが2だと、idはmonster_idです。

編集 履歴 (0)
  • ご回答ありがとうございます。
    たしかに各テーブルからそれぞれとって、そこからさらに絞るという方法が一番シンプルだと思いました。
    railsを使っているので、各50件ずつ取る所はSQLで書いて、そのarrayをsort_byでソートする方法でいこうと考えました。
    ありがとうございました。
    -

前のご質問に書いたようなUNIONしてORDER BYする方法だと多分パフォーマンスが出ないので、1つのテーブルにまとめてしまったほうがいいんじゃないでしょうか。

[ActionHistory]
 id
 action_time
 user_id
 action_type → 'Attack','GetItem'など
 action_param1 → 'Attack'ならmonster_id,'GetItem'ならitem_idなど

メリット
・アクションの追加(仕様変更)が楽
・user_idでの絞り込みも同時に可能

デメリット
・item_idやmonster_idでのテーブル結合がしづらくなる

編集 履歴 (0)
  • お返事ありがとうございます。
    たしかに一つのテーブルにまとめる方がパフォーマンスが出そうですね。勉強になりました。
    ただ私の例の書き方が悪かったのですが、action_paramは一つとは限らず、物によっては3、4つになる可能性がありました。
    なので、各テーブル毎にデータを取って、統合する方法でいこうと考えました。
    ありがとうございました。
    -
ウォッチ

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