2016-05-10 4 views
0

レコードを照会したいが、用語を指定したい。例えば、時間の間にクエリを実行しますが、期間を指定します

Home.where(created_at: Time.parse("12pm")..Time.parse("4:00pm")) 

このアクティブレコードは、12:00 pmから4:30 pmまでのすべてのレコードを取得します。そして結果は荒れ狂った記録になるでしょう。

id |  start_at  
---+--------------------- 
1 | 2008-03-03 12:00:00 
2 | 2008-03-04 12:10:00 
3 | 2008-03-05 12:30:00 
4 | 2008-03-08 12:50:00 
5 | 2008-03-09 13:00:00 
6 | 2008-03-10 13:10:00 
7 | 2008-03-13 13:20:00 
8 | 2008-03-14 13:50:00 
9 | 2008-03-14 14:00:00 
10 | 2008-03-14 14:10:00 
11 | 2008-03-14 14:30:00 
12 | 2008-03-14 14:50:00 
13 | 2008-03-14 15:00:00 
14 | 2008-03-14 15:30:00 
15 | 2008-03-14 15:50:00 
16 | 2008-03-14 16:00:00 
17 | 2008-03-14 16:10:00 

しかし、私は以下のように1時間ごとにすべてのレコードを取得したいと思います。

id |  start_at  
---+--------------------- 
1 | 2008-03-03 12:00:00 
5 | 2008-03-09 13:00:00 
9 | 2008-03-14 14:00:00 
13 | 2008-03-14 15:00:00 
16 | 2008-03-14 16:00:00 

アクティブレコードでどのようにクエリできますか?ありがとう。

答えて

1

問題を解決するための最も効率的な方法ですが、あなたは幸運です。 extract機能を使用してこれを行う方法は非常に簡単で、組み込みの方法があります。

Home.where("extract(hour from created_at) BETWEEN :min AND :max", min: 12, max: 16) 
    .where("extract(minute from created_at) = 0") 

これはあなたが多くを行うに何かあれば、おそらく、もう少し洗練された範囲は理にかなって:

class Home < ActiveRecord::Base 
    scope :hour_range, ->(min, max){ 
    created_hour = Arel::Nodes::NamedFunction.new('extract', [Arel::Nodes::SqlLiteral.new('hour from "homes"."created_at"')]) 

    where created_hour.between(min..max) 
    } 

    scope :top_of_hour, ->{ 
    where Arel::Nodes::NamedFunction.new('extract', [Arel::Nodes::SqlLiteral.new('minute from "homes"."created_at"')]).eq(0) 
    } 
end 

うん平野ARELが上のActiveRecordのDSLなしで醜いですが、それは非常に多いです強力です。私はActiveRecordのラインの外側に色を付けるだけで、Arelが本当にそのような場合に役立つことがあることを知ることができます。

0

あなたは、このためのクエリを作成するトリッキーな時間を持っているかもしれません。この

24.times do |t| 
     result = Home.where(created_at: (Date.today.beginning_of_day+ (3600*t))) 
     puts result 
    end 
+0

私はこれを考えましたが、複数のクエリを要求しました。 – Penguin

+0

'result = Home.all result.each do | t | の場合tt.created_at.min == 0 && tt.created_at.sec == 0 puts "--------------- >>>#{t}" else puts " ====== >>#{t} " end end' –

+0

あなたのコードを編集して編集します。 –

-1

を試してみてください。あなたのデータベースは時刻/日付の値を整数として格納している可能性があることを覚えておいてください。異なる日に1728000と1814400が同じ時間であることを理解していないので、「2016-05-04 12PM」と「2016- 05-05 12PM」。 恐ろしく非効率的になるだろう

  1. def query_hours(start_date, end_date, start_hour, end_hour) 
        cur_date = start_date 
        range = [] 
    
        while cur_date <= end_date 
        if cur_date.hour >= start_hour && cur_date.hour <= end_hour 
         range << cur_date 
        end 
        cur_date += 3600 
        end 
    
        range 
    end 
    
    Home.where created_at: query_hours(
        Date.new(2016, 5, 1), 
        Date.new(2016, 5, 31), 
        12, 
        16 
    ) 
    

    これは厄介である、として照会する値の配列を作成します。

    は、データセットによっては、私は2つの可能性の高いオプションを参照してくださいあなたがその日の小さな部分だけを照会しているならば。あなたは、あなたの設定された時間範囲だけをループするように最適化することができます。

  2. ホームモデルにcreated_hourアトリビュートを追加して直接照会することをお勧めします。あなたがデータベースとしてPostgreSQLの選択ので、これは重要なクエリである場合、それは

    # in your model class 
    class Home 
        after_commit :update_created_hour 
    
        def update_created_hour 
        if created_at.minute = 0 && created_at.sec == 0 
         self.created_hour = created_at.hour 
        else 
         self.created_hour = nil 
        end 
        save! 
        end 
    end 
    
    # to query 
    from = Time.parse("12pm").hour 
    to = Time.parse("8pm").hour 
    Home.where('created_hour >= ? AND created_hour <= ?', from, to) 
    
+0

ええ、そうです。単に 'created hour'を追加すると最適な解決策になります。しかし、私は他の解決策を見つけたいと思っていますが、おそらく何もありませご回答有難うございます。 – Penguin

+0

これはばかげて過剰に設計されています。データベースを使用します。 –

関連する問題