Return date as year - ruby-on-rails

I wrote this little search query:
User.where("strftime('%Y', birthday) = ?", 1994)
But somehow i get no search resuts although i now that i have several users with their birthday in 1994. In the Users Table birthday is defined as date
Now i have two ideas how i could solve my problem:
1.I could check what the result of "strftime('%Y', birthday) is for a specific user or the whole user collection. But i dont know the expression! Maybe you know the expression?
2.You know what i did wrong and you have an answer?
Thanks!

In Rails you can write the query like:
User.where("birthday BETWEEN '?-01-01' AND '?-12-31'",1994,1994)
See this post for why this kind of format is good performance-wise when compared to something that uses "YEAR": SQL query where() date's year is $year.

Your mileage may vary but I've gotten around some of these issues by querying the date column using it's underlying string format...
User.where("birthday like ?", "1994-%")
I'm too lazy to checkout sqlite's support for regexen but if you can use them then you could also try
User.where birthday: /^1994-\d{2}-\d{2}/

you should use something like
User.where("YEAR(birthday) = ?", 1994)
Ref:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_year

Related

Activerecord query against array column using wildcard

So let's say i have a Customer model with array column phones.
It's pretty easy to find all customers with given phone
Customer.where('? = ANY(phones)', '+79851234567')
But i can't figure out how to use LIKE with wildcard when i want to find customers with phones similar to given one, something like:
Customer.where('ANY(phones) LIKE ?', '+7985%')
I'm using PostgreSQL 9.5 and Rais 4.2
Any ideas?
I think, first of all, its better to use second table phones with fields customer_id, phone_number. I think it's more rails way ). In this way you can use this query
Phone.where("phone_number LIKE ?", '%PART%').first.customer
If you serialize your array in some text field, by example JSON, you should use % on both sides of your pattern:
Customer.where('phones LIKE ?', '%+7985%')
If you have an array in your database, you should use unnest() function to expand an array to a set of rows.
Can you try this
Customer.where("array_to_string(phones, ', ') like ?", '+7985%')
I believe this will work.

Get first entry from an associated table Ruby on Rails

I have a one to many relationship: User has many Payments. I am trying to find a query that gets the first payment of each user(using created_at from the payments table).
I have found a similar question with an SQL response, but I have no idea how to write it with Active Record.
how do I query sql for a latest record date for each user
Quoting the answer:
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 me, it would be min instead of max.
Thank you :)
Try this one for POSTGRES
Payment.select("DISTINCT ON(user_id) *").order("user_id, created_at ASC")
And For SQL
Payment.group(:user_id).having('created_at = MAX(created_at)')
If I'm going to answer the question above with: (I don't based on given raw SQL)
User has many Payments. I am trying to find a query that gets the first payment of each user(using created_at from the payments table).
Let say:
# Assumed to have a Single User, as reference
user = User.first
# Now, get first payment (from Payment model)
user.payments.last
# .last since it will always get the first created row by created_at.
If I fully understand what you're trying to do. I'm don't know why you need max or min date?
What about this?
If you want first payment of each user
dates = Payment.group(:user_id).minimum(:created_at).values
payments = Payment.where(created_at: dates)
From payment you can find user too.
I think you have username as foreign key, you can change accordingly. :)
Let me know if you face any issue, as I tested it works.
I know this answer is not the best, but it will work even or transactions with milliseconds difference, as rails saves date(created_at and updated_at) with ms level.
I am sorry for not replying to everything, but after multiple tests, this is the quickest answer (in run time) I came with:
Payment.where(:id => Payment.group(:user_id).pluck(:id))
I am saying it might not be the quickest way because I am using a sub query. I am getting the unique values and getting the ID's:
Payment.group(:user_id).pluck(:id)
Then I am matching those ID's.
The downside of this is that it won't work reversed, for getting the last payment.
There was also a possibility to use group_by and map but, since map is coming from ruby, it is taking much more time.
I'm not sure but try this :
In your controller :
def Page
#payments = Payment.first
end
in your html.erb :
<% #payments.each do |payment| %>
<p> <%= payment.amount %> </p>
Hope this help !
Record.association.order(:created_at).first

How to make Active Record join return unique objects?

I have a simple query need: Find a list of users who made an order since Jan 1, 2013.
In SQL, it's a very simple query.
But I'm using Rails and Active Record.
So I wrote: User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'")
In our database, we have 100 orders made since 01/01/2013 by 75 users. (Some users made more than one order apparently.)
However, the expression above returns 100 users. (There must be duplicates.)
I tried User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'").uniq
That doesn't work either.
How can I get the 75 users who've made an order since 01/01/2013?
#dbjohn has the right idea, but I assume you want to avoid creating extra objects. Here's a slight variant on his solution, letting the database do the uniq-ing for you:
date = "2013-01-01 00:00:00"
User.joins(:orders).where("orders.created_at >= ?", date).distinct
Note that you can rearrange the order of methods to fit whatever you think is most semantic, and ActiveRecord will write the same SQL for you.
User.joins(:orders).
where("orders.created_at >= '2013-01-01 00:00:00'").
group('users.id')
group method will chain to the query and give you a list of unique records.
You can write nested query like this:
User.where(id: User.joins(:orders).where("orders.created_at >= '2013-01-01 00:00:00'").ids)
Rails has added uniq since version 3.2.1
so now you can use uniq
http://apidock.com/rails/ActiveRecord/QueryMethods/uniq

Rails & Sqlite question - comparing dates to db timestamps

I'm trying to do this: map the total sales on a day to an array of dates for highcharts (yes my project is effectively exactly the same as the railscast example).
I'm unfortunately just ending up with a lot of 0s; I believe the piece in my model:
def self.total_revenue_on(date)
where("date(created_at) = ?", date).sum(:amt)
end
is failing to match the date to the datetime written in my database, e.g. "2011-07-21 09:22:28.388944+0000". Pretty sure that's where it's failing because if I remove the timezone piece manually from my database (get rid of "+0000" and leave just "2011-07-21 09:22:28.388944") it works just fine.
I think this is really a rails/sqlite question: am I storing the timestamp improperly, or comparing improperly? Any help is greatly appreciated!
The best practice is to use to_s(:db) for referencing datetimes in a database in Rails. Try:
def self.total_revenue_on(date)
where("date(created_at) = ?", date.to_s(:db)).sum(:amt)
end
OK, I managed to solve this by using a different lookup method:
def self.total_revenue_on(date)
where("datetime >= ? and datetime < ?", date, date + 1.day).sum(:amt)
end
Still completely perplexed by the problem with the original, but this seems to be working.

Ruby On Rails Querying From a model but returning another tables fields

active_courses_past_week = CourseEnrollment.select("courses.*").
joins(:course).
where("date(course_enrollments.created_at) BETWEEN ? and ?", Date.parse(start_date.strftime('%Y-%m-%d')), Date.parse(end_date.strftime('%Y-%m-%d'))).
group("courses.id")
The above query seems odd because I am querying from course enrollments, but only care about the course data where they are enrolled between two dates. It just seems weird because I am not using any of the fields in the CourseErnollment model. Any suggestions?
This is how I would write it using a range instead of "raw" SQL.
active_courses_past_week = CourseEnrollment.where(:created_at => start_date..end_date))
.joins(:course)
.group(courses.id)

Resources