繁体   English   中英

ActiveRecord的加入以及位置

[英]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.

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