Active Record query for latest update record - ruby-on-rails

I got a small problem that can't be fix now by me ^_^ and would like to see your advice.
The problem is only about getting the latest updated of several record from mysql table.
Here is the sample data but the real one has thousands of record.
Id site_id updated_at value
1 1 "2012-05-14 09:04:02" 5
2 2 "2012-05-14 09:04:02" 8
3 2 "2012-05-15 09:04:02" 9
4 3 "2012-05-16 09:04:02" 7
5 1 "2012-05-17 09:04:02" 5
6 1 "2012-05-18 09:04:02" 3
and I want to have XXXX function that will return
Id site_id updated_at value
6 1 "2012-05-18 09:04:02" 3
4 3 "2012-05-16 09:04:02" 7
3 2 "2012-05-15 09:04:02" 9

Something like this?
YourModel.order("updated_at desc").limit(3)

Assuming your model is called Account:
Account.joins("LEFT OUTER JOIN accounts a
ON a.site_id = accounts.site_id AND a.value > accounts.value").
where("a.value IS NULL").order("accounts.updated_at DESC").limit(3)

Related

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.

Get all records from one table that are not in either column of a second table

I have a Player model and a Match model. Each Match has a winner_id and a loser_id for the winning and losing Player.
How can I get all players that have never been in a match?
I.e. get all player ids, that are in neither the winner_id nor the loser_id column.
I'm using Rails 4.
Players
-------------
id
1
2
3
4
5
6
7
Matches
-------------
winner_id loser_id
1 2
1 3
1 4
So the result should be players 5, 6, and 7.
Player.where.not(id: Match.pluck(:winner_id,:loser_id).flatten.uniq)
There might be some better way also. but you can do it like this also:
ids = Matche.select(:winner_id).distinct.map{|match| match.winner_id} + Matche.select(:loser_id).distinct.map{|match| match.loser_id}
#players = Player.where.not(id: ids)

How can i count a column doing a condition?

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

How to store word compositions in a relational database in a normalized way?

I'm trying to find a nice way to store word compositions of the following form:
exhaustcleaningsystem
exhaust cleaning system
exhaustcleaning system
exhaust cleaningsystem
The combinations are given by a default per case. Every word in a composition is stored as a unique row in table 'labels'.
labels
id value
--------------------------
1 exhaustcleaningsystem
2 exhaust
3 cleaning
4 system
5 exhaustcleaning
6 cleaningsystem
I thought about a new table called 'compositions':
compositions
id domain_id range
----------------------
1 1 2,3,4
2 1 5,4
etc...
But storing multiple separated values in a column isn't normalized design. Any ideas for that?
BTW: I'm using MySQL und ActiveRecord/Rails.
The design you propose is not even in first normal form, since range is not atomic
The schema I'd use here would be
compositions
id domain_id
-------------
1 1
2 1
compositions-content
composition_id rank label_id
------------------------------------------
1 1 2
1 2 3
1 3 4
2 1 5
2 2 4
with composition_id referencing an composition.id and label_id referencing label.id
The rank column is optional and should be here if and only if the range you define here is order-sensitive.
With this design, you have some referential integrity at DB level.
Well, this is as far as I can think of in terms of normalisation:
sets
id domain_id
--------------
1 1
2 1
etc...
compositions
id set_id label_id order
---------------------------
1 1 2 1
2 1 3 2
3 1 4 3
4 2 5 1
5 2 4 2
etc...

Resources