How to merge two double joins in ActiveQuery - ruby-on-rails

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

Association in rails Model

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.

How to write correct and efficient code in Ruby in Rails equal to SQL

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')

Rails 4 SQL query rails way

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

Chain wheres with joins ActiveRecord

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' }

How to create Rails models with multiple complex associations/joins?

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.. :)

Resources