How compare time range using created_at fields on rails - ruby-on-rails

I need to get the records only included on time range using default created_at Rails field. No matters the day was created.
I have this:
#start_time = test.start_time.strftime("%I:%M%p")
#end_time test.end_time.strftime("%I:%M%p")
#websites = device.websites.where(:created_at => #start_time..#end_time)
I was searching for something like this:
#websites = device.websites.where(:created_at::time => #start_time..#end_time)
This generate this SQL sentence without results.
SELECT DISTINCT `websites`.* FROM `websites` WHERE `websites`.`device_id` = 2 AND (`websites`.`created_at` BETWEEN '16:10:00' AND '21:10:00')
But if I add time function to created_at field, works fine.
SELECT DISTINCT `websites`.* FROM `websites` WHERE `websites`.`device_id` = 2 AND (time(`websites`.`created_at`) BETWEEN '16:10:00' AND '21:10:00')
How is the best Rails way to do this ?

Rails automatically converts the time objects to the format that your database requires, so there is no need for strftime. You should be able to do it like this:
#websites = device.websites.where(:created_at => test.start_time..test.end_time)

Related

Rails group records by month using db query

Hi I am trying to find a simple way to expand my db query and group the records shown by month (Ideally I would like next month stored in "Next Page"). Is there a way to do this?
Current query
#submissions = Submission.where(:Desired_Location => current_agent.Company_Business_Location)
Thanks
First get month name from your date field and then use group method to group by month
#submissions = Submission.where(:Desired_Location => current_agent.Company_Business_Location).group('strftime('%m', your_date_field)')
In your case I would suggest to group by year as well. In that case use this:
#submissions = Submission.where(:Desired_Location => current_agent.Company_Business_Location).group('strftime('%Y %m', your_date_field)')

How to get a most recent value group by year by using SQL

I have a Company model that has_many Statement.
class Company < ActiveRecord::Base
has_many :statements
end
I want to get statements that have most latest date field grouped by fiscal_year_end field.
I implemented the function like this:
c = Company.first
c.statements.to_a.group_by{|s| s.fiscal_year_end }.map{|k,v| v.max_by(&:date) }
It works ok, but if possible I want to use ActiveRecord query(SQL), so that I don't need to load unnecessary instance to memory.
How can I write it by using SQL?
select t.username, t.date, t.value
from MyTable t
inner join (
select username, max(date) as MaxDate
from MyTable
group by username
) tm on t.username = tm.username and t.date = tm.MaxDate
For these kinds of things, I find it helpful to get the raw SQL working first, and then translate it into ActiveRecord afterwards. It sounds like a textbook case of GROUP BY:
SELECT fiscal_year_end, MAX(date) AS max_date
FROM statements
WHERE company_id = 1
GROUP BY fiscal_year_end
Now you can express that in ActiveRecord like so:
c = Company.first
c.statements.
group(:fiscal_year_end).
order(nil). # might not be necessary, depending on your association and Rails version
select("fiscal_year_end, MAX(date) AS max_date")
The reason for order(nil) is to prevent ActiveRecord from adding ORDER BY id to the query. Rails 4+ does this automatically. Since you aren't grouping by id, it will cause the error you're seeing. You could also order(:fiscal_year_end) if that is what you want.
That will give you a bunch of Statement objects. They will be read-only, and every attribute will be nil except for fiscal_year_end and the magically-present new field max_date. These instances don't represent specific statements, but statement "groups" from your query. So you can do something like this:
- #statements_by_fiscal_year_end.each do |s|
%tr
%td= s.fiscal_year_end
%td= s.max_date
Note there is no n+1 query problem here, because you fetched everything you need in one query.
If you decide that you need more than just the max date, e.g. you want the whole statement with the latest date, then you should look at your options for the greatest n per group problem. For raw SQL I like LATERAL JOIN, but the easiest approach to use with ActiveRecord is DISTINCT ON.
Oh one more tip: For debugging weird errors, I find it helpful to confirm what SQL ActiveRecord is trying to use. You can use to_sql to get that:
c = Company.first
puts c.statements.
group(:fiscal_year_end).
select("fiscal_year_end, MAX(date) AS max_date").
to_sql
In that example, I'm leaving off order(nil) so you can see that ActiveRecord is adding an ORDER BY clause you don't want.
for example you want to get all statements by start of the months you should use this
#companey = Company.first
#statements = #companey.statements.find(:all, :order => 'due_at, id', :limit => 50)
then group them as you want
#monthly_statements = #statements.group_by { |statement| t.due_at.beginning_of_month }
Building upon Bharat's answer you can do this type of query in Rails using find_by_sql in this way:
Statement.find_by_sql ["Select t.* from statements t INNER JOIN (
SELECT fiscal_year_end, max(date) as MaxDate GROUP BY fiscal_year_end
) tm on t.fiscal_year_end = tm.fiscal_year_end AND
t.created_at = tm.MaxDate WHERE t.company_id = ?", company.id]
Note the last where part to make sure the statements belong to a specific company instance, and that this is called from the class. I haven't tested this with the array form, but I believe you can turn this into a scope and use it like this:
# In Statement model
scope :latest_from_fiscal_year, lambda |enterprise_id| {
find_by_sql[..., enterprise_id] # Query above
}
# Wherever you need these statements for a particular company
company = Company.find(params[:id])
latest_statements = Statement.latest_from_fiscal_year(company.id)
Note that if you somehow need all the latest statements for all companies then this most likely leave you with a N+1 queries problem. But that is a beast for another day.
Note: If anyone else has a way to have this query work on the association without using the last where part (company.statements.latest_from_year and such) let me know and I'll edit this, in my case in rails 3 it just pulled em from the whole table without filtering.

How do I get the first row in a record after ordering it? Ruby On Rails

I am working with Ruby on Rails.
I make a query to the model, but I want to get the one register that has the highest value for the average attribute. This is my code:
#dish = Dish.where("day = ? and week = ?", params[:day], params[:week])
#dish.order(:average)
#sug = #dish.first
#sug gets the record with the lowest id, no the one with the highest average.
I have also tried it this way:
#sug = #dish.order(:average).limit(1)
but it's not working either. How can I get that one register?
You need to chain the calls like follows.
#dish.order(:average).first
The call to .order does not change the #dish instance, so when you call #dish.first the ordering no longer is there.
#dish.order does not order already found dishes, it changes the query to include an order clause.
#dish = Dish.where("day = ? and week = ?", params[:day], params[:week]).order(:average) would do what you wanted, and so would
#dish = Dish.where("day = ? and week = ?", params[:day], params[:week])
#dish = #dish.order(:average)
#sug = #dish.first
The ActiveRecord::QueryMethods#order method sorts in ascending order by default, so try explicitly asking for a descending order, then taking the first:
Dish.order(average: :desc)
.where("day = ? and week = ?", params[:day], params[:week])
.first
This assumes your average attribute is stored in the database, and not computed.

activerecord comparing times

i am trying to do a query that will be compare the time stored in the database to the current time, and if it is greater than today to display those records.
below is query i am currently using that isnt displaying any records
#schedules = Schedule.where(:team_id => current_user[:team_id], :event => '1', :time => ">= Time.now.zone")
how do i go back query against a timestamp? so that these records will be displayed?
have also tried the following
#schedules = Schedule.find_all_by_team_id_and_event_and_time(current_user[:team_id],"1", :time)
#schedules = Schedule.where("team_id = ? and event = ? and time >= ?", [current_user[:team_id], "1", Time.zone.now])
The string is used directly in the SQL query so you need to make sure the column names are correct and unambiguous (if you joined on another table that also has a team_id colum, you would need to do schedules.team_id = ? and ...)

Trying to create a subquery using activerecord in rails 3

I am very new to rails. Thanks for taking a look at this. I'm trying to create essentially a subquery in activerecord. Here is what I have in my controller.
#vote_time = Submission.select("submissions.updated_at").where(:chosen => true).first
#submissions = Submission.where(["submissions.created_at > ?", #vote_time])
I think this is roughly what it would look like in sql.
select * from submissions where submissions.created_at < (select submissions.updated_at from submissions where chosen = true limit 1)
Whenever I run the activerecord search #vote_time is inserted as null. Am I just barking up the wrong tree? Can you not pass a variable into an array condition? Thank you so much for your time.
You want to call the updated_at attribute on the first object returned, rather than trying to select only that column. As so:
#vote_time = Submission.where(:chosen => true).first.updated_at
#submissions = Submission.where(["submissions.created_at > ?", #vote_time])

Resources