简体   繁体   English

具有多级关联的Rails复杂查询

[英]Rails complex query with multi level associations

I have a deeply nested layout as follows: 我有一个深层嵌套的布局,如下所示:

Contract -> has many Packages -> has many Services 合同->有很多套票->有很多服务

Payment -> belongs_to Invoice -> belongs_to Contract 付款->属于发票->属于合同

class Contract < ActiveRecord::Base
  has_many :invoices
  has_many :contract_packages
  has_many :packages, through: :contract_packages
end

class Package < ActiveRecord::Base
  has_many :services
  has_many :contract_packages
  has_many :contracts, through: :contract_packages
end

class ContractPackage < ActiveRecord::Base
  belongs_to :contract
  belongs_to :package
end

class Service < ActiveRecord::Base
  belongs_to :package
end

class Invoice < ActiveRecord::Base
  belongs_to :contract
end

class Payment < ActiveRecord::Base
  belongs_to :invoice
end

I want to find what Services, and how many times were invoiced in a certain period of time, based on payment date. 我想查找基于付款日期的哪些服务,以及在一定时间内开具发票的次数。 Invoice date may not be the same as payment date. 发票日期可能与付款日期不同。

I know hot to do it by pure SQL, and it works, but I am stuck if I want to do it the rails way. 我知道通过纯SQL进行此操作很热,并且可以正常工作,但是如果我想以rails的方式进行操作,我会陷入困境。

Any ideas? 有任何想法吗?

Edit: 编辑:

The pure sql query: 纯SQL查询:

select s.[name], count(*), s.[price] from payments p 
left join invoices i on p.invoice_id=i.id
left join contracts c on i.[contract_id]=c.id
left join contract_packages cp on cp.contract_id=c.id
left join packages pk on cp.[package_id]=pk.id
left join services s on s.package_id=pk.id
where ... conditions
group by s.id
order by s.id asc

In my original question I left out, for brevity, a join table, because a package may belong to many contracts. 为了简洁起见,在我最初的问题中,我省略了一个联接表,因为一个包可能属于许多合同。 The sql here includes the join table. 此处的sql包括连接表。 I updated the models also. 我也更新了模型。

Doing joins in in activerecord is quite straight forward as long as you have defined the relationships in your models. 只要在模型中定义了关系,就可以在activerecord中进行联接。 You just pass a hash to joins and it figures out what keys to use. 您只需传递一个散列来joins ,它就可以确定要使用哪些键。 Adding the where conditions can be done in similar fashion. 可以以类似方式添加where条件。

I noticed that there was no has_many :payments in your invoice is this by design? 我注意到您的发票中没有has_many :payments这是设计has_many :payments In that case why? 在那种情况下为什么呢?

The select clause I have written will give all Service objects created with this query an extra method count where you will find your value. 我编写的select子句将为使用此查询创建的所有Service对象提供额外的方法count ,您可以在其中找到您的值。

Service.select('*, count(*) as count')
.joins({ 
  package: { 
    contract: {
      invoices: :payment
    } 
  }
})
.where(conditions_hash)
.group('services.id asc')
.order(:id)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM