【问题标题】:SQL: how to find a complement to a set with a derived function/valueSQL:如何找到具有派生函数/值的集合的补集
【发布时间】:2009-06-10 22:58:45
【问题描述】:

这个问题把我难住了,所以我希望比我聪明的人能帮助我。

我正在做一个 Rails 项目,其中我有一个用户模型,它有一个关联的 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

然而,反过来 - 找到所有当前被打卡的用户 - 看似困难。我最终使用了以下命名范围定义,尽管它很老套:

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)

有人有更好的方法吗,或者这真的是唯一的处理方法吗?

【问题讨论】:

    标签: sql ruby-on-rails ruby


    【解决方案1】:

    除了@Eric 的建议之外,还有一个问题(除非您以其他方式保证不会向我们展示)用户可能没有任何时钟周期——然后是内部join 将无法包含该用户,并且他不会显示为打卡或打卡。假设您还想将这些用户显示为已下班,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 - 好点子,我想过这个问题,但是在我写答案的时候忘记了。
    【解决方案2】:

    假设 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
    

    【讨论】:

      【解决方案3】:

      在 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])
      

      至少,我认为这会奏效......

      【讨论】:

        猜你喜欢
        • 2019-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-20
        相关资源
        最近更新 更多