In Ruby on Rails I'm doing something like:
Appointment.find( :first, :conditions => "staff_id = #{staff_id} AND datetimefield = #{datetime}")
... where datetimefield is of course, a datetime field. But, I only want rows where the date is equal to a given day, say 2/12/2011. I don't care about the time. What's an easy way to do this?
Thanks!
SELECT * FROM TheTable WHERE DATE(TheField) = '2010-02-12';
One possibility is to query for the value being between midnight and 23:59:59 on the target day, something like:
datetimefield = BETWEEN #{datetime.strftime('%Y-%m-%d 00:00:00')} AND #{datetime.strftime('%Y-%m-%d 23:59:59')}"
Another option (not recommended if your column is indexed, because you'll almost certainly invalidate the use of that index) could be something like this:
"strftime('%Y-%m-%d', datetimefield) = #{datetime.strftime('%Y-%m-%d')}"
Related
I have a table where I need to create a new entry or update if one of the columns is inside a range of dates (today).
For example, I have a table of shuttles registration with [name, time] where name represents someone and time is when he would like to take the shuttle on.
Each (name) can register at most once a day.
When someone registers, I would like to update an existing row (of the same day), if exists, or create a new one.
The following query extracts the relevant row, if exists:
Shuttle.where('name= ? AND time BETWEEN ? AND ?', params[:name], DateTime.now.beginning_of_day, DateTime.now.end_of_day)
Tried to use first_or_create and equivalents but couldn't find the right syntax to apply the range query.
Any idea?
Thanks
Try this:
Shuttle.where(:name => params[:name]).
where(:time => DateTime.now.beginning_of_day..DateTime.now.end_of_day)).
first_or_create(:time => DateTime.now)
Reference: http://guides.rubyonrails.org/v3.2.13/active_record_querying.html#first_or_create
first_or_create doesn't apply in this scenario, because the condition doesn't make sense as the value of an update. It would be like saying "Find a shuttle where the time is any time on this given day, and if you don't find one then create one where the time is any time on this given day". That doesn't make sense: you need a specific time when you create a shuttle.
You need to think about the logic of what you want to do: it's not obvious to me at least.
If I understand you, I would do the following
#shuttle = Shuttle.where('name= ? AND time BETWEEN ? AND ?', params[:name], DateTime.now.beginning_of_day, DateTime.now.end_of_day).first
#shuttle.columnname = "new value"
#shuttle.save
If you are doing multiple
#shuttles = Shuttle.where('name= ? AND time BETWEEN ? AND ?', params[:name], DateTime.now.beginning_of_day, DateTime.now.end_of_day)
#shuttles.each do |shuttle|
shuttle.columnname = "new value"
shuttle.save
end
What about something like this?
#shuttle = Shuttle.where(
name: params[:name],
time: DateTime.now.beginning_of_day..DateTime.now.end_of_day
).first_or_initialize do |s|
s.attribute = value
s.save
end
I have to update an age column based on the value in a date of birth column. There are thousands of records to update.
How do I do this using rails?
Is this the right way to do it?
User.update_all(:age => some_method);
def some_method
age = Date.today.year - dob.year
end
Yes, update_all is the right method but no, you can't do it like this. Your some_method will only get called once to set up a database call (I assume you're persisting to a database). You'll then get an error because dob won't be recognised in the scope of the User class.
You'll need to translate your date logic to SQL functions.
Something like (for mysql):
User.update_all("age = year(now()) -
year(dob) -
(DATE_FORMAT(now(), '%m%d') < DATE_FORMAT(dob, '%m%d'))")
(NB. the date_format stuff is so that you get the right age for people who's birthdays are later in the year than the current date - see this question for more details)
The other option is to use one of the batches functionality in rails.
User.where(some_condition).find_in_batches do |group_of_users|
# some logic
# e.g. group_of_users.update_all(:age => some_logic)
end
This would lock your db for less time. Note that you should pretty much always update with a condition in mind. I can't think of many cases you would want to update an entire table every time something happens.
There are a few options checkout the rails docs or the api.
your query is right.
There are many way to update record in a batch/lot.
But, I think that your query is best. Because it is rails query that will support every condition for all database.
for updating more than one attributes
Model.update_all(:column1 => value1, :column2 => value2, ........)
or
you can use :
Model.update_all("column1 = value1, column2 = value2, ........")
I have a a Model with integer date field format like this: 20131211. What would be the appropriate Activerecord query to select all of the objects that have exact same numbers apart from the ones I'd like to replace? So in my case its 201312NN or in someone else's it could be 1234NN78.
I could go with something like
scope :show_query, lambda { where('startdate <= and enddate >= ?', 20131201, 20131231) }
but isn't there a better way?
If you date is really a integer just divide by 100
scope : show_query, lambda { where ('date DIV 100 = ?', 201312) }
Alternatively you can use like :
where('date like ?', '201312__')
But that's slower.
With MySQL you don't need to convert the date to a String, I'm not sure if it's standard SQL or not.
I'm passing my Rails controller a parameter that has a value of:
time = "2011-11-14T23:53:14.000Z"
For my app, I have a a database called "Reminders" with a remind_at column, which is a datetime column just like created_at and modified_at.
However I can't figure out how I should save this. I imagine it would be something like:
r = Reminder.create(:remind_at => time)
r.save
But this does not save it properly. Am I supposde to do some conversion of some sort first? Any thoughts?
Yes, you need to convert it into a Time object:
time = Time.parse("2011-11-14T23:53:14.000Z")
Is it possible to do an activerecord query that only looks at the time component of a datetime field?
e.g. Battle.where('start_time < ? and start_time > ?','12:00','06:00')
to find all battles that were started between 6am and 12pm regardless of the day they occurred? In this example, start_time is defined as a datetime.
The only way to do this is using a SQL function, if you're on MySQL you could do it like this:
Battle.where( 'HOUR( start_time ) >= ? AND HOUR( start_time ) <= ?', 12, 6 )
But this is hugely inefficient and is always going to generate a full table scan and you surely don't want that.
The best solution is to add columns with the hour values alone at your battle model, index them and query directly on them like this:
Battle.where( 'start_time_hour >= ? start_time_hour <= ?', 12, 6 )
Just add an before_save callback that sets this values before saving your Battle model based on the start_time property.
EDIT
BTW, if you're using PostgreSQL, it's capable of creating an index on the result of a function, so, if you don't mind having to stick with PostgreSQL you could just use the SQL function. And before you ask, no, i don't know how it works, I only know the database allows you to do so and that this is not available on MySQL.