[英]ActiveRecord joins and where
我有三个模型Company,Deal和Slot。 它们与公司has_many交易和Deal has_many插槽关联。 如果所有A公司的交易都已到期,则所有A公司都可以到期。 当交易的所有广告位都到期时,交易也会到期。
我已经写了一个范围。
scope :expired,
lambda { |within|
self.select(
'DISTINCT companies.*'
).latest(within).joins(
:user =>{ :deals => :slots }
).where(
"companies.spam = false AND deals.deleted_at IS NULL
AND deals.spam = false AND slots.state = 1
OR slots.begin_at <= :time",
:time => Time.zone.now + SLOT_EXPIRY_MARGIN.minutes
)
}
从我要实现的目标来看,上述范围对我来说似乎不合适。 我需要所有交易时段都处于状态1或begin_at小于:time使其过期的公司。
感谢您提前查看。
并具有比或SQL让你一个更高的优先级where
实际被解析如下:
(
companies.spam = false
and deals.deleted_at is null
and deals.spam = false
and slots.state = 1
)
or slots.begin_at <= :time
例如(为简洁起见,略有修饰):
mysql> select 1 = 2 and 3 = 4 or 5 = 5;
+---+
| 1 |
+---+
mysql> select (1 = 2 and 3 = 4) or 5 = 5;
+---+
| 1 |
+---+
mysql> select 1 = 2 and (3 = 4 or 5 = 5);
+---+
| 0 |
+---+
另外,您可能希望在SQL中使用占位符而不是文字上的false
,如果您要切换数据库,这应该会使事情变得更容易(但是,数据库可移植性在很大程度上是一个神话,所以这只是一个建议); 您也可以只在SQL中not
使用。 此外, 使用类方法是接受scope参数的首选方法 。 如果其他作用域已经在起作用,则使用scoped
而不是self
也是一个好主意,但是如果您使用类方法,则不必在意。
如果我们在SQL中用一些括号修复了分组,请为false
使用占位符,然后切换到类方法:
def self.expired(within)
select('distinct companies.*').
latest(within).
joins(:user => { :deals => :slots }).
where(%q{
not companies.spam
and not deals.spam
and deals.deleted_at is null
and (slots.state = 1 or slots.begin_at <= :time)
}, :time => Time.zone.now + SLOT_EXPIRY_MARGIN.minutes)
end
如果您喜欢少量的SQL而不是一个大的SQL,也可以这样编写:
def self.expired(within)
select('distinct companies.*').
latest(within).
joins(:user => { :deals => :slots }).
where('not companies.spam').
where('not deals.spam').
where('deals.deleted_at is null').
where('slots.state = 1 or slots.begin_at <= :time', :time => Time.zone.now + SLOT_EXPIRY_MARGIN.minutes)
end
这也巧妙地避免了您的“缺失括号”问题。
更新 :基于评论中的讨论,我认为您正在追求像这样的事情:
def self.expired(within)
select('distinct companies.*').
latest(within).
joins(:user => :deals).
where('not companies.spam').
where('not deals.spam').
where('deals.deleted_at is null').
where(%q{
companies.id not in (
select company_id
from slots
where state = 1
and begin_at <= :time
group by company_id
having count(*) >= 10
)
}, :time => Time.zone.now + SLOT_EXPIRY_MARGIN.minutes
end
最底层的麻烦是获取具有十个或更多已过期或已使用插槽的所有公司ID,然后companies.id not in (...)
company.id会将它们从最终结果集中排除。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.