Given the following models:
class PeriodBilling < ActiveRecord::Base
belongs_to :appcode
belongs_to :period
belongs_to :sla
belongs_to :unit_type
belongs_to :dpc_employee
belongs_to :general_ledger
end
class GeneralLedger < ActiveRecord::Base
has_many :appcodes
has_many :sla_task_details
belongs_to :expense_category
has_many :period_billings
has_many :expected_billings
end
How would I find the following SQL equivalent in Rails, to display as a matrix with periods down the left side and general_ledgers across the top, with the sum(pb.current_amt) in the appropriate fields?
select pb.pe_number, gl.general_ledger_number, sum(pb.current_amt)
from period_billings pb, general_ledgers gl
where pb.sla_id = 21
and pb.general_ledger_id = gl.id
group by pb.pe_number, gl.general_ledger_number
In Active Record terms, this is kinda what I'm trying to find:
#sla = Sla.find(params[:id])
#period_billings = PeriodBilling.where("sla_id = ?", #sla.id).group_by(&:general_ledger_id)
#billing_sum = #period_billings.inject(0){|sum,billing| sum+billing.current_amt}
So, I want to find all period_billings for the selected sla, grouped by general_ledger_id to get the sum of the period_billing.current_amt for those records. Then, I want to put the 12 periods down the side to show the summed amount in its appropriate general_ledger column across the top.
Thanks in advance!!! :)
Just a wild little stab at what I suggest you do. Some things are better meant for direct sql, and when that arises, like you're requesting, it's best to just use sql.
ActiveRecord::Base.connection.execute <<-EOF
select pb.pe_number, gl.general_ledger_number, sum(pb.current_amt)
from period_billings pb, general_ledgers gl
where pb.sla_id = 21
and pb.general_ledger_id = gl.id
group by pb.pe_number, gl.general_ledger_number
EOF
Related
I have included client_person and case_histories but when querying case_histories it still generates n+1 query.
I have tried for a long while but nothing seems to work.
#client_records = #records.includes({person: [:client_person, :case_histories]})
In person model:
belongs_to :client_person, class_name: 'Client::Person'
has_many :case_histories, through: :region_profiles, class_name: 'Admin::PeopleCaseHistory'
the query that generates n+1:
#client_records.each do |record|
record.person.case_histories.select{ |hist| hist.case_type == 2}.first
end
Specifically, after correctly loading the case_histories for all clients in the list(resulting from the includes clause), it still one by one queries for the case_histories of each client.
The first query generated by includes:
Admin::PeopleCaseHistory Load (46.9ms) SELECT "case_histories".* FROM "case_histories" WHERE "case_histories"."region_profile_id" IN (411, 16804, 572, 19506, 16539, 692, 4828)
The subsequent N+1 queries:
Admin::PeopleCaseHistory Load (29.5ms) SELECT "case_histories".* FROM "case_histories" INNER JOIN "region_profiles" ON "case_histories"."region_profile_id" = "region_profiles"."id" WHERE "region_profiles"."person_id" = $1 [["person_id", 9867]]
Admin::PeopleCaseHistory Load (34.3ms) SELECT "case_histories".* FROM "case_histories" INNER JOIN "region_profiles" ON "case_histories"."region_profile_id" = "region_profiles"."id" WHERE "region_profiles"."person_id" = $1 [["person_id", 430]]
Please advise!
Thanks
Looks like you have both people_region_profile_id and region_profile_id on your case_histories table. One of those is getting used during eager-loading, but the other is not.
It would help for you to list out your entire model/relation graph because I'm unable to construct what exactly is going on. It seems to me that your graph looks something like this:
class Person < ActiveRecord::Base
belongs_to :client_person
has_many :region_profiles
has_many :case_histories, through: :region_profiles
end
class RegionProfile < ActiveRecord::Base
belongs_to :person
has_many :case_histories
end
class CaseHistory < ActiveRecord::Base
belongs_to :region_profile
end
But clearly I'm missing something if case_histories have two different foreign keys.
Here what I have now :
class Pokemon < ActiveRecord::Base
has_many :pokemon_moves, dependent: :destroy
has_many :moves, through: :pokemon_moves
end
class PokemonMove < ActiveRecord::Base
belongs_to :pokemon
belongs_to :move
end
class Move < ActiveRecord::Base
belongs_to :type
end
And many others, no important.
I just would like to search for a Pokémon which could have Move named "pound" and another Move "mega-punch"
I tried :
Pokemon.joins(:moves).where(moves: {name: 'pound'}).where(moves: {name: 'mega-punch'})
But no result. The translated SQL is :
SELECT "pokemons".* FROM "pokemons" INNER JOIN "pokemon_moves" ON "pokemon_moves"."pokemon_id" = "pokemons"."id" INNER JOIN "moves" ON "moves"."id" = "pokemon_moves"."move_id" WHERE "moves"."name" = $1 AND "moves"."name" = $2 [["name", "pound"], ["name", "mega-punch"]]
If I only search for one move, it works just fine, but I can't get it with two moves.
I have tried many things, but all concludes to bad results.
Of course, I have a Pokémon that have those moves, if I do Pokemon.find_by_name('golurk').moves I can retrieve those two moves.
Thanks !
UPDATE 1 :
I made it work by simply using & operator :
Pokemon.joins(:moves).where(moves: {name: 'pound'}) & Pokemon.joins(:moves).where(moves: {name: 'mega-punch'})
But it's really not efficient, and I'm pretty sure we can find a better way.
The reason you get no results is because you are searching for moves with the name pound AND the name mega punch.
Change your code to:
Pokemon.joins(:moves).where(moves: {name: ['pound', 'mega-punch']})
Chaining where results in AND in your sql. If you want OR, either use an array like in the example above, or write your own sql.
I have a model project and payment
class Project < ActiveRecord::Base
has_many :payments, :dependent => :destroy
end
class Payment < ActiveRecord::Base
belongs_to :project
end
I am trying to find projects which have total sum of its payments higher than is project target amount
#projects=Project.joins(:payments).where('enabled = true and amount < sum(payments.amount)')
this shows me error thay my attempt is too ambiguous
How should I compare field by sum from joined table?
Firstly your error is because of both table have same column name amount you can solve this error using projects.amount but aggregate function i.e sum is not allow in where clause of sql. you can use group by clause with having this way:
#projects=Project.joins(:payments).group("payments.project_id").where('enabled = true').having("sum(payments.amount) > projects.amount")
you can also try this way beacuse PG not support other column to select which are not in group by clause:
#projects=Project.includes(:payments).where("projects.id = payments.project_id and enabled = true").select{ |p| p.amount < p.payements.sum(&:amount) }
ok I've found a solution how to use proposed mysql answer on postgres
Project.select("projects.*").joins(:payments).group("projects.id").where('enabled = true').having("sum(payments.amount) > projects.amount")
found it here
https://github.com/rails/rails/issues/1515
I have two models, ParentProfile and RoomParentAssignment:
class ParentProfile < ActiveRecord::Base
has_many :room_parent_assignments
and
class RoomParentAssignment < ActiveRecord::Base
belongs_to :room_parent_profile, class_name: 'ParentProfile', foreign_key: 'parent_profile_id'
I would like to retrieve all ParentProfile records where there are no room_parent_assignments. I'm looking for something like the following statement (which needless to say, is invalid):
#non_room_parents = ParentProfile.where(!room_parent_assignments.present?)
How would I do this?
The below query should do
ParentProfile.joins("left outer join room_parent_assignments on room_parent_assignments.parent_profile_id = parent_profiles.id").where(room_parent_assignments: {parent_profile_id: nil})
use the below code:
parent_ids = RoomParentAssignment.select(parent_profile_id)
#non_room_parents = ParentProfile.where.not(:id => parent_ids)
You have two options here:
OPTION 1
#non_room_parents = ParentProfile.where.not(id: RoomParentAssignment.all.map(&:parent_profile_id))
OPTION 2
#non_room_parents = ParentProfile.where("id NOT IN (?)", RoomParentAssignment.all.map(&:parent_profile_id))
Both of them are equal to get no parent rooms.
have model
Class ModelA < ActiveRecord::Base
has_many :apples
before_save :include_prime_apple_in_apples
has_one :prime_apple
def include_prime_apple_in_apples
self.apple_ids << prime_apple_1.id
end
end
l=ModelA.new(:apple_ids => [ "ap_1_id", "ap_2_id"],:prime_apple => prime_apple_1)
l.save
l.apple_ids.should include(prime_apple_1.id) # this doesnt seem to work
How change the params passed for associations?
There's something wrong there but to answer your question:
AFAIK you can only assign to "other_ids". Also you can push directly to the has_many relation:
self.apple_ids = self.apple_ids + [prime_apple_1.id]
or
self.apples << prime_apple_1
Do you have different foreign_key set in the Apple model?
has many will do a select * from apples where modela_id = X
has one will do a select * from apples where modela_id = X limit 1
Which means that whatever you'll set on the prime_apple accessor you'll get back the first Apple record ...