Activerecord或SQL语句,用于查找联接表中发生特定事件的用户

时间:2016-01-31 15:18:18

标签: sql ruby-on-rails postgresql activerecord

我有一个与my_ersy MyVersions关联的用户。 每次在User中更改“profile_id”或“state”列时,都会创建一个MyVersion。 MyVersion有以下列:

user_id, object_changed (profile_id or state), before, after

我需要查找处于活动状态且在特定时间具有特定配置文件的用户。意思是,在相关的my_versions中发生这种情况时查找所有用户:

  1. my_versions是在日期之前创建的,其中:object_changed是'州'并且在该时间范围内: 1.1然后(不是AND)找到最后一个,只有当以下值为'活动'时才选择用户

  2. my_versions是在日期之前创建的,其中:object_changed是'profile_id'并且在该时间范围内:
    2.1那么找到最后一个并且只选择用户,如果:after的值为'1'

  3. 仅选择与1.1和2.1匹配的用户
  4. 编辑1:显然我越来越接近但仍然不确定这是否能满足我的需求:

    active_user_ids = User.joins(:my_versions).merge(MyVersion.where(
      "my_versions.created_at = (SELECT MAX(created_at) from my_versions WHERE
        user_id = users.id AND created_at < '2016-01-01' AND object_changed = 'state')
      AND my_versions.after = 'activo'")).pluck(:id)
    

    现在我拥有当时处于活动状态的所有用户IDS(是吗?)。然后我可以对配置文件执行相同操作,但也传递以前的IDS以正确组合结果:

    active_and_right_profile =
      User.joins(:my_versions).merge(MyVersion.where(
      "my_versions.created_at = (SELECT MAX(created_at) from my_versions WHERE
        user_id = users.id AND created_at < '2016-01-01' AND object_changed = 'profile_id')
      AND my_versions.after = 1")).where(id: active_user_ids)
    

    它看起来不漂亮,我不确定我是否在规格中得到了我上面描述的内容。第一次测试似乎是正确的,但我有很多疑问,因为我不理解查询的某些部分:

    • 显然,当我使用“SELECT MAX ... where user_id = users.id”时,我要求每个用户ID的最高值。是对的吗?
    • 如果这是真的,我得到了一系列结果,我将它传递给第一个created_at =。这意味着如果我在此查询范围之外的其他版本但具有确切的时间戳,则它们将在结果中。那是对的吗?这与我有关,因为很少有那些versions.created_at正在手动更新。

    它看起来如何?有没有办法让它只用一个查询更好?有没有办法避免搜索我上面提到的确切的created_at值?

    谢谢!

    以前的尝试:
    我试过这个:

    Class User...
    
    scope :active_at, -> (date) {
      joins(:my_versions).merge(MyVersion.on_state.before_date(date)
      .where("my_versions.created_at = (SELECT MAX(created_at) FROM my_versions WHERE user_id = users.id AND after = 'activo')"))
    }
    

    但这会创建以下查询:

    SELECT `users`.* FROM `users` INNER JOIN `my_versions` ON `my_versions`.`user_id` = `users`.`id` WHERE `my_versions`.`object_changed` = 'state' AND (my_versions.created_at < '2016-01-31') AND (my_versions.created_at = (SELECT MAX(created_at) FROM my_versions WHERE user_id = users.id AND after = 'activo'))
    

    这不是我需要的。

0 个答案:

没有答案