Let's say that I have a Model called Game.
That model have two fields, start_date (timestamp) and time_limit (integer)
I want to select all objects, that will return true to following statement:
start_date + time_limit.minutes > Time.now
I managed to get all objects where start_date is greater than time now, but that's not what I exactly wanted.
Game.where(["start_date > ?", Time.now])
How should I do it?
PostgreSQL
Game.where("start_date > now() - time_limit * interval '1 MINUTE'")
As start_date + time_limit.minutes > Time.now this is a simple inequation you can also write the same as: start_date > Time.now - time_limit.minutes
So your query should be:
Game.where(["start_date > ?", Time.now - time_limit.minutes])
✌️
Related
I'm trying to find all the records that have a specific channel_id, and were made less than 1 day ago. The query finds the records with the given channel_id but does not respect the date restriction. Instead, it returns records created at any date.
#discussions = Discussion.where('channel_id = ? and created_at > ?', current_user.subscription.pluck(:channel_id), 1.days.ago )
I expected to only get the Discussions that had relevant subscriptions channel_id, and were made less than 1 day ago. But instead, this query ignores the created at restriction but returns the Discussions that had the corresponding subscriptions channel ID.
#discussions = Discussion.where("channel_id IN (?) AND DATE(created_at) >= ?", current_user.subscription.pluck(:channel_id), (Date.today - 1.day))
OR
#discussions = Discussion.where("channel_id IN (?) AND created_at >= ?", current_user.subscription.pluck(:channel_id), (Date.today - 1.day).end_of_day)
Or
Discussion.where("DATE(created_at) >= ?", (Date.today - 1.day))
.where("channel_id IN (?)", current_user.subscription.pluck(:channel_id))
#discussions = Discussion.where("channel_id = :channel AND created_at > :date", channel: current_user.subscription.pluck(:channel_id), date: Date.yesterday )
I have a model, Product, which has both a :created_at timestamp and an :expiration_in_days attribute. Products are considered expired a certain number of days after their creation. How do I write a query that only returns products that have not expired?
Rails 4, Ruby 2.1, PG 0.17
I have been trying queries like this, with no success:
#product.rb
def self.not_expired
where('created_at + expiration_in_days * 86400 >= ?', Time.now)
end
I have a pure Ruby version that works fine, it's just slower:
#product.rb
def self.not_expired
select{ |p| (p.created_at.to_i + p.expiration_in_days * 86400) >= Time.now.to_i}
end
note, the 86400 calculation converts the the :expiration_in_days integer into seconds
Any pointers on more advanced Rails queries than the documentation (http://guides.rubyonrails.org/active_record_querying.html) would be very welcome as well.
Thanks in advance.
Try this:
def self.not_expired
where("created_at + (expiration_in_days * 86400)::text::interval >= ?", Time.now)
end
UPDATE: Add references
You can learn more about date and time function here.
Given your case has a special requirement, which is the value of expiration_in_days is a column in the table, we cannot use created_at + interval expiration_in_days day. Instead, we need to type cast its value to interval. But you can't type cast straight to an integer, that's why we cast it to text first.
A + B > C is true if A <= C - B
So, instead of trying to add the expiration time to created_at, subtract the expiration time from Time.now.
def expiration_threshold
Time.now - amount_of_time # I'm not sure what type to use
end
def self.not_expired
where( "created_at > ? ", expiration_threshold )
end
I've always been a little stumped about what type Rails/Ruby will want when dealing with various dates/times, you may have to play around.
I'm not sure if this would work but try something like this
def self.not_expired
where("TIMESTAMP created_at + INTERVAL '1 day' * expiration_in_days >= NOW()")
end
I'm trying to find records whose start and end date range over a particular date. Date is random and :start_date and :end_date are attributes of the prices entity.
date = Time.now
record_i_want = Price.where(date => :start_date .. :end_date)
Thank you.
You can simply do
Price.where(:date => start_date..end_date)
This will result in the following SQL( for start and end dates - '2014-03-27', '2014-03-28')
SELECT `prices`.* FROM `prices` WHERE (`prices`.`date` BETWEEN '2014-03-27' AND '2014-03-28')
EDIT:
Realized that this is the query you are looking for. Thanks, Coenwulf for pointing it out
Price.where(['start_date < ? AND end_date > ?', date, date])
You want to select rows where your date is greater than the start_date and less than the end_date. You can specify the appropriate SQL where clause parameterized in your call to where like so:
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today})
That will give you all the prices that match. If you know you'll get only one you can get it by calling first.
Price.where([":date >= start_date AND :date <= end_date", {date: Date.today}).first
Make any appropriate adjustment to the >= and <= if you want to exclude the start_date and/or the end_date from the results. If for example the Price is valid starting on the start_date but isn't valid through the end_date you can change the clause to:
":date >= start_date AND :date < end_date"
This should work:
def get_record_by_date(date)
Price.where([start_date.to_i < date.to_i] && [end_date.to_i > date.to_i])
end
I have a object and a result table
Object has_many Results
Result belongs_to Object
Result has a column called kg.
I need to get for each object the kg data
where('DATE(created_at) = ?' Date.today AND Date.today - 1.day AND Date.today - 1.week AND Date.today - 1.month)
So my question is, which is my best option:
Get all the records for 1 month (date Between today and today - 1.month) and then get the result for today, yesterday, 1 week ago and 1 month ago)
today = result.where("DATE(created_at) BETWEEN ? AND ?", Date.today - 1.month, Date.today)
Or make 4 queries and get the data for each date?
today = result.where('DATE(created_at) = ?' Date.today)
y = result.where('DATE(created_at) = ?' Date.today - 1.day)
w = result.where('DATE(created_at) = ?' Date.today - 1.week)
m = result.where('DATE(created_at) = ?' Date.today - 1.month)
Depending on how you want to later use the results, it might make sense to query them individually using your second approach. That way, you don't have to further separate them in your resultset.
If you don't actually need the data you query in your first approach, it doesn't make sense to retrieve them from the database. You should then use another, more specific approach.
If your actual queries are more complicated that the one shown in the question or if you just want a single result set, it might make sense to use the following approach which just requires one query:
dates = [
Date.today,
Date.today - 1.day,
Date.today - 1.week,
Date.today - 1.month
]
resultset = Result.where('DATE(created_at) IN (?)', dates)
This query will result in a SQL query similar to this:
SELECT * from results WHERE DATE(created_at) IN ('2013-12-16', '2013-12-15', '2013-12-09', '2013-11-16');
You should be able to build an IN request.
result.where('DATE(created_at) IN (?)', [Date.today, Date.today - 1.day])
Which will retrieve the records which are in between the provided dates.
I'm building an events app that is very simple, it has a title and start_date and end_date. I would like to filter my query by mixing some of the values, like: if the start_date has passed but the end_date has not, the event is active and should be displayed. If both dates have passed, it should be omitted, too. I think that scopes is the aswer, but I only was able to filter the records within the view using some methods shown below.
I really would like to filter the query that is passed to the controller (#events). I want to show all events that are active, have a future start_date, or a past start_date but are still in progress (Today's date is in range between start_date and end_date)
EDITED
I have made some scopes which return each part of the query. Chaining them actually substracts the results instead of merging them. So i have used this code and actually works do I do not know how solid or DRY this is. Looks kind of ugly to me... is this a decent way to merge queries in rails 3?
scope :active, where("active = ?", true)
scope :not_over_or_in_progress, lambda { where("start_date < ? AND end_date > ? OR end_date IS NULL AND start_date > ? OR end_date IS NOT NULL AND start_date > ?", Date.today, Date.today, Date.today, Date.today) }
scope :valid, not_over_or_in_progress.active.order("start_date DESC")
Try using scopes:
class Event < AR::Base
scope :active, lambda { |date| where("start_date < ? AND end_date > ?", date) }
scope :future, lambda { |date| where("end_date < ?", date }
...
end
# Console
> #active_events = Event.active(Date.today)
> #future_events = Event.future(Date.today)
See http://guides.rubyonrails.org/active_record_querying.html