,並具有比或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