Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rails 4中的复杂SQL查询_Sql_Ruby On Rails 4 - Fatal编程技术网

Rails 4中的复杂SQL查询

Rails 4中的复杂SQL查询,sql,ruby-on-rails-4,Sql,Ruby On Rails 4,我有一个复杂的查询,我需要在我的Rails应用程序中设置一个作用域,我尝试了很多事情,但都没有成功。我通过find_by__SQL求助于原始SQL,但我想知道是否有大师想尝试一下。为了清楚起见,我将把措辞简化一点,但应该准确地说明问题 我有用户。用户拥有许多记录。其中一个标记为当前(#is#u current=true),其余标记为非当前。每个记录都有许多关系。关系有一个“当它们处于活动状态时”(active_when)的值,它有四个值[1..4] 值1和2被认为是最近的。值3和4不适用 问题最

我有一个复杂的查询,我需要在我的Rails应用程序中设置一个作用域,我尝试了很多事情,但都没有成功。我通过find_by__SQL求助于原始SQL,但我想知道是否有大师想尝试一下。为了清楚起见,我将把措辞简化一点,但应该准确地说明问题

我有用户。用户拥有许多记录。其中一个标记为当前(#is#u current=true),其余标记为非当前。每个记录都有许多关系。关系有一个“当它们处于活动状态时”(active_when)的值,它有四个值[1..4]

值1和2被认为是最近的。值3和4不适用

问题最终是在用户上有一个作用域(has_recent_relationships和has_no_recent_relationships),用于筛选当前记录上是否有最近的关系。(旧记录与此无关。)我尝试在关系上创建最近和非最近的作用域,然后在记录上构建作用域,并检查is_current==1。这就是我失败的地方。我必须继续使用该应用程序,但别无选择,只能使用原始SQL并继续使用该应用程序,希望稍后再次访问。我把它放在用户上,这是我真正需要的唯一上下文,并为其他对象上的作用域留出代码

下面是能够正确查找最近有关系的用户的SQL。另一个只在HAVING子句中使用“=0”而不是“>0”

SELECT * FROM users WHERE `users`.`id` IN (
  SELECT 
    records.owner_id
  FROM `coi_records`
  LEFT OUTER JOIN `relationships` ON `relationships`.`record_id` = `records`.`id`
  WHERE `records`.`is_current` = 1
  HAVING (
    SELECT count(*)
    FROM relationships
    WHERE ((record_id = records.id) AND ((active_when = 1) OR (active_when = 2)))
  ) > 0
)
我的直觉告诉我,这已经够复杂了,我的建模可能需要重新设计和简化,但是单个对象非常简单,仅仅从两个对象中获取特定数据就变得复杂了


不管怎样,我希望你能有任何想法。我不希望有一个完整的解决方案,因为,呃。我想你们当中的受虐狂可能会觉得这很有趣。

你有没有试过直接使用阿雷尔和阿雷尔

只需复制并粘贴查询,即可获得以下结果:

User.select(Arel.star).where(
  User.arel_table[:id].in(
    Relationship.select(Arel.star.count).where(
      Arel::Nodes::Group.new(
        Relationship.arel_table[:record_id].eq(Record.arel_table[:id]).and(
          Relationship.arel_table[:active_when].eq(1).or(Relationship.arel_table[:active_when].eq(2))
        )
      )
    ).joins(
      CoiRecord.arel_table.join(Relationship.arel_table, Arel::Nodes::OuterJoin).on(
        Relationship.arel_table[:record_id].eq(Record.arel_table[:id])
      ).join_sources
    ).ast
  )
)

我设法找到了一种方法来创建我需要的返回ActiveRelationship对象的内容,这简化了许多其他代码。这是我想到的。这可能无法很好地扩展,但这个应用程序可能不会有太多的数据,这将是一个问题

我创建了两个作用域方法。第二种方法依赖于第一种方法来简化事情:

def self.has_recent_relationships
  joins(records_owned: :relationships)
  .merge(Record.current)
  .where("(active_when = 1) OR (active_when = 2)")
  .distinct
end

def self.has_no_recent_relationships
  users_with_recent_relationships = User.has_recent_relationships.pluck(:id)
  if users_with_recent_relationships.length == 0
    User.all
  else
    User.where("id not in (?)", users_with_recent_relationships.to_a)
  end
end
第一种方法通过加入记录、与选择当前记录(应该只有一个)的作用域合并来查找具有最近关系的用户,并在值出现时查找正确的活动\u。很简单


第二种方法查找最近有关系的用户(使用第一种方法)。如果没有,则所有用户都在最近没有关系的用户集中,我返回User.all(这在野外永远不会发生,但理论上可能发生)。否则,我返回最近有关系的用户的相反结果,使用SQL关键字NOT IN和数组。如果阵列变大,这一部分可能会失效,但我暂时同意。

感谢您的回复,marzapower。我确实试过阿雷尔,但当时没有时间深入研究。不过,我会为那个网站制作一个书签!看起来很有用!请看我发布的答案,了解我是如何让它工作的,至少现在是这样。