I have two double joins (I believe that's what they would be considered) and it just seems awfully slow to do them separately. I know there are debates as to whether or not an individual query is quicker than multiple queries and vice versa but I am willing to try anything.
Here are my existing statements:
line_stops = OpsHeader.joins(
ops_stop_rec: :driver_header
)
.select(
:pbbname,
:pb_net_rev,
:ops_driver1,
:pb_id,
:ops_stop_id,
:dh_first_name,
:dh_last_name,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
})
line_items = OpsHeader.joins(
ops_stop_rec: :ops_line_items
).select(
:pbbname,
:opl_amount,
:pb_id,
:ops_type,
:ops_stop_id,
:ops_order_id,
:ops_driver1,
:ops_delivered_time
)
.where(
:ops_stop_rec => {
ops_arrive_time: params[:startDate] .. params[:endDate]
}
)
Just for reference, I am pulling these from an old Firebird Database and the server hardware is not necessarily quick either, so there may be more at play than I am thinking. Also, I have to data manipulation on top of that before I serve it to the client.
Anyway, here are my associations:
class OpsHeader < ApplicationRecord
belongs_to :pb_bill
belongs_to :pb_master
has_many :ops_stop_rec, foreign_key: 'ops_order_id'
self.table_name = 'OPS_HEADER'
self.primary_key = 'pb_id'
end
class OpsStopRec < ApplicationRecord
#belongs_to :ops_order
#belongs_to :ops_im_equip
belongs_to :ops_header, foreign_key: 'pb_id'
belongs_to :driver_header, foreign_key: 'ops_driver1'
has_many :ops_line_items, foreign_key: 'opl_stop_id'
self.table_name = 'OPS_STOP_REC'
self.primary_key = 'ops_stop_id'
end
class OpsLineItem < ApplicationRecord
#belongs_to :opl_order
#belongs_to :opl_stop
belongs_to :ops_stop_rec, foreign_key: 'ops_stop_id'
self.table_name = 'OPS_LINE_ITEMS'
self.primary_key = 'opl_stop_id'
end
class DriverHeader < ApplicationRecord
#belongs_to :dh_paythru
has_many :ops_stop_rec, foreign_key: 'ops_driver1'
self.table_name = 'DRIVER_HEADER'
self.primary_key = 'dh_id'
end
What you're looking for is a union operator. There is a gem which can handle it for you.
Or try using using two left outer joins and add an OR condition.
Related
Below is the model Structure.
class UserFamilyRole < ActiveRecord::Base
belongs_to :user_family
belongs_to :user_role
belongs_to :organization
end
class UserFamily < ActiveRecord::Base
has_many :user_family_roles
has_many :user_roles
end
I am looking for below result from the above UserFamilyRole table.
{
user_family1: [user_role1, user_role2],
user_family2: [user_role1, user_role2, user_role3]
...
}
I achieved this Result from below query:
user_family_roles = UserFamilyRole.where(:organization_id => org_id)
results = {}
juser_family_roles.each do |user_family_role|
user_family = UserFamily.find(user_family_role.user_family_id)
result[user_family.name] = user_family.user_roles.collect(&:title)
end
puts results
But Above query doesn't look optimized one so can anyone help me to write the optimized query.
In our App org_id is present.
I stucked and I don't know how to write correct query in RoR to achieve active record.
Relations between tables:
imed_patient has one imed_operator
imed_operator has many imed_operator_contacts
imed_patient has_many imed_operator_conatc through imed_operator
Definition of models :
class ImedOperator < ActiveRecord::Base
self.table_name = "imed_operator"
self.primary_key = "code"
has_one :imed_patient, foreign_key: 'r_opr_code'
has_many :imed_operator_contact, :foreign_key => "r_opr_code"
end
class ImedOperatorContact < ActiveRecord::Base
self.table_name = "imed_operator_contact"
end
class ImedPatient < ActiveRecord::Base
self.table_name = "imed_patient"
self.primary_key = "code"
has_many :visit, :foreign_key => "r_ptn_code"
belongs_to :imed_operator , foreign_key: 'r_opr_code'
has_many :imed_operator_contact, through: :imed_operator
end
Good SQL in PostgreSQL:
select * from imed_patient
INNER JOIN imed_operator ON imed_patient.r_opr_code = imed_operator.code
INNER JOIN imed_operator_contact ON imed_operator.code = imed_operator_contact.r_opr_code
where (imed_operator_contact.r_ct_id = 1 or imed_operator_contact.r_ct_id = 2) and imed_operator_contact.value = '501'
Code now (not working) is:
#pacjenci = ImedPatient.ImedOperatorContact.where('imed_operator_contact.r_ct_id = ? or imed_operator_contact.r_ct_id = ? and imed_operator_contact.value = ?',1,2,'+48501')
Error during run:
NoMethodError in PacjenciController#szukajpacjenttel undefined method
`ImedOperatorContact' for #
Anybody can help me ?
SOLVED
Thanks guys for inspiration. I solved it by:
#pacjenci = ImedPatient.joins(:imed_operator).joins(:imed_operator_contact).where('imed_operator_contact.value' => '+48501', 'imed_operator_contact.r_ct_id' => [1,2])
I used information from here point 12.1.3.2 Joining Nested Associations (Multiple Level)
Special Thanks to Andy
Try adding this to your ImedPatient:
has_many :imed_operator_contacts, through: :imed_operator
With that you should be able to use any ActiveRecord/arel style query:
imed_patient.imed_operator_contacts.where(value: '501')
i have this query, which I want to se in rails way. Could please anyone help me here?
select * from users
,buyer_events
,supplier_events
where (users.id = buyer_events.buyer_id
or users.id = supplier_events.supplier_id)
and supplier_events.event_id = 11
and buyer_events.event_id = 11;
PostgreSQL
If more information is needed just write in comments :)
I guess it should be something like this:
class User
has_many :supplier_events
has_many :buyer_events
scope :with_event, ->(event_id) {
joins(:supplier_events, :buyer_events).merge(supplier_events.for_event(event_id)).merge(buyer_events.for_event(event_id))
}
end
class SupplierEvent
belongs_to :supplier, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
class BuyerEvent
belongs_to :buyer, class_name: :User
belongs_to :event, class_name: :Event
scope :for_event, ->(event_id) { where(event_id: event_id) }
end
Then issue:
User.with_event(11)
class User < ActiveRecord::Base
...
def self.buyers_and_suppliers user_id
joins(:buyer_events, :supplier_events).where(users: {id: user_id}, supplier_events: {event_id: 11}, buyer_events: {event_id: 11})
end
...
end
I'm trying to do something like this:
filter_categorys = params[:filter_categorys]
companies = Company.where('id_category = (?)', filter_categorys).joins(:subsidiary).where('zone = Nuñez')
And it's not working....
So, I need to get all my companies that have an id_category and that they have at least one subsidiary within the 'zone'.
I guess this is not the way... please HELP ! :D
Company.rb:
class Company < ActiveRecord::Base
has_many :subsidiary, :foreign_key => :id_company
has_many :benefit, :foreign_key => :id_company
set_primary_key :id_company
self.table_name = 'tbl_companys'
end
Subsidiary.rb:
class Subsidiary < ActiveRecord::Base
belongs_to :company
set_primary_key :id_subsidiary
self.table_name = 'tbl_subsidiaries'
end
You have to "tell" the where clause that the zone is in the subsidiary table:
Company.where(id_category: filter_categorys).joins(:subsidiary).where(subsidiary: { zone: 'Nuñez' }
If it says "relation subsidiary was not found", try with:
Company.where(id_category: filter_categorys).joins(:subsidiary).where(tbl_subsidiaries: { zone: 'Nuñez' }
I am trying to figure out how to create ActiveRecord models with associations that can yield the same results as this SQL query:
SELECT login, first_name, last_name, email_address
FROM accounts
INNER JOIN people ON person.id = accounts.person_id
INNER JOIN email_address_people ON person.id = email_address_people.person_id
INNER JOIN email_addresses ON email_address.id = email_address_people.email_address_id
INNER JOIN email_address_types ON email_address_types.id = email_address_people.email_address_type_id
WHERE email_address_types.email_address_type = 'account';
The table structure is as follows, and assumes each table has an id per normal ActiveRecord convention:
accounts
id : int
person_id : int
login : string
people
id : int
first_name : string
last_name : string
email_address_people
id : int
person_id : int
email_address_id : int
email_address_type_id : int
email_addresses
id : int
email_address : string
email_address_types
id : int
email_address_type: string
I need the models to be fully functional, and not limited by things like :find_by_sql.
How do I create the associated models that make this possible?
Thanks!
Chris Benson
chris#chrisbenson.com
Try this:
Your model classes:
class EmailAddress < ActiveRecord::Base
end
class EmailAddressType < ActiveRecord::Base
end
class People < ActiveRecord::Base
has_many :accounts
has_many :email_address_people
has_many :email_addresses, :through => :email_address_people
has_many :account_email_address_people,
:class_name => "EmailAddressPeople",
:conditions => "email_address_type = 'account'"
has_many :account_email_addresses,
:through => :account_email_address_people
end
class EmailAddressPeople < ActiveRecord::Base
belongs_to :person
belongs_to :email_address
belongs_to :email_address_type
end
Your account model:
class Account < ActiveRecord::Base
belongs_to :person
# now to the actual method
def account_emails
person.account_email_addresses.map do |email|
[login, person.first_name, person.last_name, email.email_address]
end
end
# Brute force SQL if you prefer
def account_emails2
sql = "YOUR SQL HERE"
self.connection.select_values(sql)
end
end
Assuming you have the Account object in hand account.account_emails makes two database calls:
Get the person using a id
Get the account emails for the person
Going directly to the database(i.e. account.account_emails2) is the fastest option, but it is not the Rails way.
I think the best thing to do here is to give you the documentation first: http://railsbrain.com/api/rails-2.3.2/doc/index.html
Look up "has_many" (paying attention to :through) and "belongs_to", as well as "has_one", although I don't think you'll use the later.
This blog post will help you with the has_many :through concept -- and I think after that, you'll be set. Let us know if there's anything that's not clear!
class Account < ActiveRecord::Base
belongs_to :person
end
class Person < ActiveRecord::Base
has_many :accounts
has_many :email_addresses :through => :email_address_people
end
class EmailAddress < ActiveRecord::Base
belongs_to :email_address_type
belongs_to :person
has_one :email_address_type
end
class EmailAddressType < ActiveRecord::Base
has_many :email_addresses :through => :email_address_people
end
I would get started with that. It's not tested, but if we see what breaks, then we can fix it.. :)