,并具有比或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
。此外,using a class method is the preferred way to accept arguments for scopes。使用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的小斑点而不是一个大的:
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
这一个也整齐地回避你的“缺少括号”的问题。
UPDATE:基于在评论的讨论,我觉得你这样的事情之后是:
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 (...)
将它们从最终结果集中排除。
在一条线上阅读令人头晕目眩,所以我把它分开了。 – tadman 2012-03-14 19:18:21
谢谢塔德曼.. – Vikram 2012-03-14 19:23:19