I have an "ITEMS" database made of; ITEM_ID, OWNER_ID and VALUE.
An owner can own unlimited items. An item can only have one owner.
And I have an "OWNER" database made of; ID, NAME
I want to find the NAMES of top 10 RICHEST (wealthier) people. How can I do that?
First, I need to sum the values of an owner_id; than compare that with others?
Here is what you can do :
Item.group(:owner_id) # grouping Items by owner id
.select("SUM(value) as sum") # summing values of each group
.order("sum DESC") # ordering resulting records by the sum value
.limit(10) # giving the top 10 records
It is kinda long solution but it worked for me:
toplist = []
all_owners = Owner.all
all_owners.each do |owner|
name = Owner.find(owner).name
owner_value = Item.where(owner_id: owner).sum(:value)
toplist << [owner_value,name]
end
#top10 = toplist.sort.last(10).reverse
Related
I have a table called vehicles, which has a column called vehicle_id and price.
I have a table called sales, which references the vehicles table. It has the columns vehicle_id (references the vehicle table) and sale_status which can equal to 'sold' or 'loan'.
I am trying to calculate the total price of vehicles which equal to 'sold' in the sales table. Help is much appreciated!
This is what I have so far but it returns the wrong number.
vehicle.rb:
def self.vehicles_price_sum
vehicles_sold.sum(:price).to_f
end
def self.vehicles_sold
Vehicle.where(id: Sale.where(sale_status: 'Sold'))
end
You can try with a subquery (which is close to you solution, yet you need to provide a column name explicitly for in clause with select, otherwise sales' id column is going to be provided):
Vehicle.where(id: Sale.where(status: "Sold").select(:vehicle_id)).sum(:price)
# SELECT SUM(`vehicles`.`price`) FROM `vehicles` WHERE `vehicles`.`id` IN (SELECT `sales`.`vehicle_id` FROM `sales` WHERE `sales`.`sale_status` = 'Sold')
Order has_many Items is the relationship.
So let's say I have something like the following 2 orders with items in the database:
Order1 {email: alpha#example.com, items_attributes:
[{name: "apple"},
{name: "peach"}]
}
Order2 {email: beta#example.com, items_attributes:
[{name: "apple"},
{name: "apple"}]
}
I'm running queries for Order based on child attributes. So let's say I want the emails of all the orders where they have an Item that's an apple. If I set up the query as so:
orders = Order.joins(:items).where(items: {name:"apple"})
Then the result, because it's pulling at the Item level, will be such that:
orders.count = 3
orders.pluck(:email) = ["alpha#exmaple.com", "beta#example.com", "beta#example.com"]
But my desired outcome is actually to know what unique orders there are (I don't care that beta#example.com has 2 apples, only that they have at least 1), so something like:
orders.count = 2
orders.pluck(:email) = ["alpha#exmaple.com", "beta#example.com"]
How do I do this?
If I do orders.select(:id).distinct, this will fix the problem such that orders.count == 2, BUT this distorts the result (no longer creates AR objects), so that I can't iterate over it. So the below is fine
deduped_orders = orders.select(:id).distinct
deduped_orders.count = 2
deduped_orders.pluck(:email) = ["alpha#exmaple.com", "beta#example.com"]
But then the below does NOT work:
deduped_orders.each do |o|
puts o.email # ActiveModel::MissingAttributeError: missing attribute: email
end
Like I basically want the output of orders, but in a unique way.
I find using subqueries instead of joins a bit cleaner for this sort of thing:
Order.where(id: Item.select(:order_id).where(name: 'apple'))
that ends up with this (more or less) SQL:
select *
from orders
where id in (
select order_id
from items
where name = 'apple'
)
and the in (...) will clear up duplicates for you. Using a subquery also clearly expresses what you want to do–you want the orders that have an item named 'apple'–and the query says exactly that.
use .uniq instead of .distinct
deduped_orders = orders.select(:id).uniq
deduped_orders.count = 2
deduped_orders.pluck(:email) = ["alpha#exmaple.com", "beta#example.com"]
If you want to keep all the attributes of orders use group
deduped_orders = orders.group(:id).distinct
deduped_orders.each do |o|
puts o.email
end
#=> output: "alpha#exmaple.com", "beta#example.com"
I think you just need to remove select(:id)
orders = Order.joins(:items).where(items: {name:"apple"}).distinct
orders.pluck(:email)
# => ["alpha#exmaple.com", "beta#example.com"]
orders = deduped_orders
deduped_orders.each do |o|
puts o.email # loop twice
end
I have an table that includes these field :
table phonebook
id
user_id
number
name
added
card_id
speeddial
updated_at
sms_group_name
some records have same sms_group_name and number,but there is some duplicate number for same sms_group_name. First I want to take distinct number for each sms_group_name and group_concat with , delimiter.
query result must be like this :
user_id, number,number,number,number,sms_group_name
select where condition is user_id
I tried all of them :
# #a = Phonebook.select(["DISTINCT number","sms_group_name"]).where(user_id: session[:user_id]).order(:sms_group_name).distinct
# #a = Phonebook.where(user_id: session[:user_id])
# Product.where.not(restaurant_id: nil).select("DISTINCT ON(name) name, restaurant_id, price, updated_at").order("name, updated_at")
# #a = Phonebook.where(user_id: session[:user_id]).select("DISTINCT ON(number) number, added, user_id, speeddial, updated_at,sms_group_name").order("sms_group_name")
# Phonebook.select("DISTINCT(number), *").where("user_id = ?", session[:user_id]).order("sms_group_name ASC").group_by(&:sms_group_name)
# Location.where("calendar_account_id = ?", current_user.calendar_accounts.first).group(:alias).order("alias ASC").group_by(&:category)
# #a = Phonebook.where("user_id = ?", session[:user_id]).order("sms_group_name ASC").group(:sms_group_name)
# #a = Phonebook.select("DISTINCT(number), sms_group_name").where("user_id = ?", session[:user_id]).order("sms_group_name ASC").group_by(&:sms_group_name)
# #a = Phonebook.select(:number)distinct.where("user_id = ?", session[:user_id]).order("sms_group_name ASC").group_by(&:sms_group_name)
# #a = Phonebook.select("DISTINCT(number), sms_group_name").group("sms_group_name")
most of them give error or does not work.
how can achive this ?
I tried select all values into object array ,after that I tried to eliminate them, but there is no suitable solution for now.
what can be solutions for both:
1- solution by using query and may be added one block
2- solution by using hash or array
best regards,
Let there is a model Item with attributes id, name and specific record in DB with name 'other'.
How to get in single SQL query an ActiveRecord::Relation object with items sorted in way that other item is at last position?
As temporarily solution I used Item.where.not(name: 'other') + Item.where(name: 'other') but it results in 2 queries.
NB: it's not a real code but an extremely simplified example.
Perhaps something like below will help - we read all Items, and use slice to remove the Item with name equal to other, and append it back to array at the end.
a = Item.all.tap do |arr|
arr << arr.slice!(arr.index { |t| t.name == "other"})
end
if i get you right then you're looking for a SQL query, right? Then you could try something like that:
select id, name
from (
select id, name, decode(name, 'other', 999, 1) as sort
from items
)
order by sort
I have no database right now to test the statement. But I think you get the idea.
Good luck
Resolved with adding class method to Item model:
def self.sorted
find_by_sql("SELECT * FROM items ORDER BY (CASE name WHEN 'other' THEN 0 ELSE 1 END) DESC, id ASC")
end
I have a joined model that has a foreign key for the model event.
The joined model is called Goals. I'm trying to find the proper find condition to figure out which event_id has the most instances in the Goal join model. Essenially which foreign key id has the most entries in the join model.
Is there a way to do this?
Goal.where(:event.id => ??????? ).first
Couldn't come up with a more elegant solution but try this:
results = Goal.connection.select_all('SELECT COUNT(*) as amount, event_id FROM goals GROUP BY event_id ORDER BY amount DESC LIMIT 0, xx')
raise results.inspect
If you just want the one most event_id with most entries you can also use:
event_id = Goal.connection.select_one('SELECT COUNT(*) as amount, event_id FROM goals GROUP BY event_id ORDER BY amount DESC LIMIT 1').first
If you have set up your models correctly you should be able to do this (if this is not the case then: setup your models correctly):
if Event.all.length == 0
return
end
eventMax = Event.first
Event.all.each do |e|
eventMax = e.goals.length>eventMax.goals.length?e:eventMax
end
#output or do whatever with your newly found event
puts eventMax.to_json
The solution from Danny is not really good.
You should never (or at least very rarely) have to write sql by yourself in rails.