How can i count a column doing a condition? - ruby-on-rails

i'm trying to count a column using conditions
Tables
select* from policies
|policies|
|id| |client_id| |expiration_date
1 1 2013-10-10
2 1 2013-10-10
3 2 2013-10-10
|clients|
|id| |name|
1 ABC
2 CDE
3 EFG
i WANT
select *,count(number_expirations) from policies where(client=1)
select *,count(number_expirations) from policies where(client=2)
|policies|
|id| |client_id| |number_of_expirations|
1 1 2
3 2 1
This is consult
#count = Policy.count('expiration_date',:joins=> :client,:conditions=>['name =?',params[:name])
But i'm trying to count expiration_date by client_id
I will really appreciate help.

i did not completely understand your question or the finder that you provided, but i think that you want to get a count of expiration_dates grouped by client.
this would look like this:
Policy.where(name: params[:name]).group(:client_id).count

Related

How to fix group in complex query in rails or do a join on two separate query results and then query again

I have been stuck with this problem for a while at work. The data given has been radically changed as I just need the general idea of how to approach the problem, and it would not be possible to provide the actual schema of the tables.
I have a table Users and and another table Membership. And each user has a one to many relationship with membership through the user_membership table. A mock up of the following table is shown below:
id
name
email
1
John
john#gmail.com
2
James
james#gmail.com
...
...
...
id
user_id
membership_id
1
2
1
2
1
2
3
1
3
4
1
4
5
1
5
...
...
...
id
created_at
1
31st Dec 2021
2
1st Jan 2022
3
2nd Jan 2022
4
3rd Jan 2022
5
4th Jan 2022
...
...
I have some level of rather complex querying that returns an ActiverecordRelation.
ie:
users = Users.select(....)
I then need to chain the above query with another query that allows each user with their latest membership_created_at date. Ie:
<User, id: 1, name: John ,email: john#gmail.com, latest_membership_created_at: 4th Jan 2022>
<User, id: 2, name: James ,email: james#gmail.com, latest_membership_created_at: 31st Dec 2021>
My approach:
users = users.joins(user_memberships: :membership).merge(User.all).group(:id).select('membership.*, MAX(membership.created_at) AS membership_created_at_raw')
I get an error:
Query 1 ERROR: ERROR: column "users.id" must appear in the GROUP BY clause or be used in an aggregate function...
Qn 1: Is there anyway I can fix this?
In another related note, is it also possible to do a join of the result of 2 queries? I am thinking perhaps I can do a group of user_membership table by user_id and join with the membership table. Something like
users_created_at = User.all.joins(user_memberships: :membership[).group(:id).select('user.id, MAX(memberships.created_at) AS membership_created_at_raw')
Qn 2: Can we then somehow do an innerjoin between users and users_created_at using rails?
Thank you!
You can do it like this:
User.select(
'DISTINCT ON (users.id) users.id, memberships.*'
).joins(
user_memberships: :membership
).order('users.id, memberships.created_at DESC')
Or raw SQL query
SELECT DISTINCT ON (users.id) users.id, memberships.*
FROM users
LEFT JOIN user_memberships ON user_memberships.user_id = users.id
LEFT JOIN memberships ON memberships.id = user_memberships.membership_id
ORDER BY users.id, memberships.created_at DESC

how can I get unique user_id from Post

How can I get unique values from column in the table? For example, I have this Products table:
user_id number
1 900
1 400
2 100
2 300
3 200
Here I used....
like so
Post.order(number: :desc).limit(3).each do |p| > I got here
user_id number
1 900
1 400
2 300
like so
Here I want "user_id" not to overlap. like this
f
user_id number
1 900
2 300
3 200
As deepak adviced, you might use distinct.
However, I guess you need to get maximum value from all records with the same user_id? Then you need to use sql to group values by user_id and selecting max from it. In Rails that might be like this. I can't tell you that it will work for sure because don't remember the output, believe it's array of hashes, it might throw the error that you're not using some other field:
Post.group(:user_id).max(:value)
it's SQL equalent:
SELECT user_id, MAX(value) FROM posts GROUP BY user_id

Rails: Possible to refactor this query?

I have 2 active record relation objects with the code as follow:
#obj1 = User.select('user.X, table2.Y, table2.Z, count (*)')
.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2, 3)
#obj2 = User.select('user.X, table2.Y, count (*)')
.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2)
Basically, the only difference between #obj1 and #obj2 is that #obj2 is not selecting table2.Z column data.
Here is a sample data that I would like both #obj to have:
#obj1
-------------------------------------
user.X table2.Y table2.Z count
-------------------------------------
1 1 A 1
1 1 B 1
2 1 A 1
2 1 B 1
2 1 C 1
#obj2
-------------------------
user.X table2.Y count
-------------------------
1 1 2
2 1 3
Currently the queries above are working fine, but I believe it is possible to further refactor the code? Like having #obj2 to get the records based on #obj1 data without having to do similar sql query? Appreciate if anyone got input on this. Many thanks in advance.
columns = %w(users.X, table2.Y table2.Z count(*))
#obj1 = User.merge(#some_variable)
.joins(:table1, :table2)
.group(1, 2, 3)
.select(*columns)
#obj2 = #obj1.select(*(columns - ["table2.Z"]))
A further step in refactoring would be to use Arel to replace the string conditions for portability.

Complex Left Outer Self-Join in Rails 5

I have a list_events table where I want to get the latest event per user per list between a certain time. Here's an example of the table.
id user_id list_id event created_at
1 5 1 sub 13:45
2 1 1 sub 14:01
3 1 2 sub 14:02
4 3 1 sub 14:03
5 4 1 sub 14:04
6 1 1 unsub 14:05
The last events per user for list 1 between 14:00 and 15:00 would be...
id user_id list_id event created_at
4 3 1 sub 14:03
5 4 1 sub 14:04
6 1 1 unsub 14:05
In my Rails 5 model I've written the query like so:
list.events
.joins("
left outer join list_events b
on list_events.user_id = b.user_id
and list_events.list_id = b.list_id
and list_events.created_at < b.created_at
")
.where("b.user_id is null")
.where(created_at: start..end)
This works fine, but I'm wondering if there's a way to write this without hand-coding the join. I do notice Rails has a left_outer_join method, but there's no way to specify custom on. Perhaps with a belongs_to?
Also if there's a way to alias list_events as a while still being able to take advantage of the list.events relationship abstraction.

Limit PER user in rails query

So I have a standard users table structure, with a primary id key and what so not and the following persona table:
user_id | persona_id | time_inserted
2 1 x
2 2 x+1
2 3 x+2
1 1 x+3
5 8 x+6
5 9 x+1
What I'd like to do is retrieve the LAST inserted row and limit to ONE per user id. So, in that query, the result I want would be:
[2, 3] because the last inserted for 2 was persona_id 3 (x+2), [1, 1], and [5,8] because the last inserted for 5 was persona_id 8 (x+6)
This is my query:
to_return = Persona.select(to_get).where(to_condition)
This works, but retrieves them all. How can I restrict the query as asked? Thank you very much.
This should work:
to_return = Persona.select(to_get).where(to_condition).group('user_id').having('time_inserted = MAX(time_inserted)')
Update
You can't select a column if you don't put that in the group clause.
As you want to group by only user_id, one possible solution is, select the user_id s first with the maximum time_inserted like this:
users_ids_relation = Persona.select('user_id').group('user_id').having('time_inserted = MAX(time_inserted)')
Then, join it with the personas table based on the condition and then select the required columns:
users_ids_relation.joins('personas').where(to_condition).select(to_get)
It will give you the expected result.

Resources