这个让我感到难过,所以我希望有比我更聪明的人可以帮助我。
我正在开发一个rails项目,其中我有一个User模型,它与clock_periods的关联加入了它,具有以下部分定义:
User
has_many :clock_periods
#clock_periods has the following properties:
#clock_in_time:datetime
#clock_out_time:datetime
named_scope :clocked_in, :select => "users.*",
:joins => :clock_periods, :conditions => 'clock_periods.clock_out_time IS NULL'
def clocked_in?
#default scope on clock periods sorts by date
clock_periods.last.clock_out_time.nil?
end
用于检索所有时钟用户的SQL查询非常简单:
SELECT users.* FROM users INNER JOIN clock_periods ON clock_periods.user_id = users.id
WHERE clock_periods.clock_out_time IS NULL
然而,反过来说 - 找到目前正在淘汰的所有用户 - 看起来很困难。我最终使用了以下命名的范围定义,尽管它是hackish:
named_scope :clocked_out, lambda{{
:conditions => ["users.id not in (?)", clocked_in.map(&:id)+ [-1]]
}}
让我感到困扰的是,似乎应该有一种方法可以在SQL中执行此操作,而无需生成如
之类的语句SELECT users.* FROM users WHERE users.id NOT IN (1,3,5)
任何人都有更好的方法,或者这真的是处理它的唯一方法吗?
答案 0 :(得分:1)
除了@ Eric的建议之外,还有一个问题(除非你保证不会以某种其他方式反对它,你没有向我们展示)用户可能没有任何时钟周期 - 然后是内部加入将无法包含该用户,并且他不会显示为时钟输入或时钟输出。假设您还希望将这些用户显示为时钟,那么SQL应该类似于:
SELECT users.*
FROM users
LEFT JOIN clock_periods ON clock_periods.user_id = users.id
WHERE (clock_periods.clock_user_id IS NULL) OR
(getdate() BETWEEN clock_periods.clock_out_time AND
clock_periods.clock_in_time)
(这种事情是外部联接的主要用途,例如LEFT JOIN
)。
答案 1 :(得分:0)
假设getdate()= SQL实现中的函数,它返回现在表示的日期时间。
SELECT users.* FROM users INNER JOIN clock_periods ON clock_periods.user_id = users.id
WHERE getdate() > clock_periods.clock_out_time and getdate() < clock_periods.clock_in_time
答案 2 :(得分:0)
在rails中,Eric H的回答应该类似于:
users = ClockPeriod.find(:all, :select => 'users.*', :include => :user,
:conditions => ['? > clock_periods.clock_out_time AND ? < clock_periods.clock_in_time',
Time.now, Time.now])
至少,我认为这样可行......