复杂的铁路查询 - 工会?子选择?我还可以使用named_scope吗?

ste*_*com 6 mysql sql union activerecord ruby-on-rails

我喜欢Rails的部分原因是我讨厌SQL - 我认为它更像是一种汇编语言,应该使用更高级别的工具(如ActiveRecord)进行操作.然而,我似乎已经达到了这种方法的极限,而且我已经超出了SQL的深度.

我有一个包含大量子记录的复杂模型.我还有一组30-40个named_scopes,它们从客户端实现业务逻辑.这些范围有条件地链接在一起,这就是为什么我有这些joins_范围所以连接不会被破坏.

我有几个不能正常工作,或者至少不是客户希望他们如何工作.这里是模型结构的粗略概念,其中有一些命名范围(不是示例所需的全部范围),用于说明我的方法并指出我的问题. (请原谅任何语法错误)

class Man < ActiveRecord::Base
  has_many :wives

  named_scope :has_wife_named       lambda { |n| { :conditions => { :wives => {:name => n}}}}
  named_scope :has_young_wife_named lambda { |n| { :conditions => { :wives => {:name => n, :age => 0..30}}}}
  named_scope :has_yw_named_v2      lambda { |n| { :conditions => ["wives.name = ? AND wives.age <= 30", n]}}
  named_scope :joins_wives         :joins => :wives

  named_scope :has_red_cat          :conditions => { :cats => {:color => 'red'}}        
  named_scope :has_cat_of_color     lambda { |c| { :conditions => { :cats => {:color => c}}}}
  named_scope :has_7yo_cat          :conditions => { :cats => {:age => 7}}
  named_scope :has_cat_of_age       lambda { |a| { :conditions => { :cats => {:age => a}}}}
  named_scope :has_cat_older_than   lambda { |a| { :conditions => ["cats.age > ?", a] }}
  named_scope :has_cat_younger_than lambda { |a| { :conditions => ["cats.age < ?", a] }}
  named_scope :has_cat_fatter_than  lambda { |w| { :conditions => ["cats.weight > ?", w] } }
  named_scope :joins_wives_cats     :joins => {:wives => :cats}
end

class Wife < ActiveRecord::Base
  belongs_to :man
  has_many :cats
end

class Cat < ActiveRecord::Base
  belongs_to :wife
end
Run Code Online (Sandbox Code Playgroud)
  1. 我可以找到那些妻子有红色和七岁的猫的男人

    @men = Man.has_red_cat.has_7yo_cat.joins_wives_cats.scoped({:select => 'DISTINCT men'})
    
    Run Code Online (Sandbox Code Playgroud)

    我甚至可以找到那些妻子有超过20磅和超过6岁的猫的男人

    @men = Man.has_cat_fatter_than(20).has_cat_older_than(5).joins_wives_cats.scoped({:select => 'DISTINCT men'})
    
    Run Code Online (Sandbox Code Playgroud)

    但这不是我想要的.我想找到他们的妻子都在他们之中至少一个红色的猫和一个七岁的猫的男人,这需要不一样的猫,或查找其妻子都在他们之中至少一只猫给定重量以上和男性一只比规定年龄大的猫.
    (在后续的例子中,请假设存在适当的joins_DISTINCT)

  2. 我可以找到名叫以斯帖的妻子

    @men = Man.has_wife_named('Esther')
    
    Run Code Online (Sandbox Code Playgroud)

    我甚至可以找到名叫Esther,Ruth OR Ada的妻子的男人(甜蜜!)

    @men = Man.has_wife_named(['Esther', 'Ruth', 'Ada'])
    
    Run Code Online (Sandbox Code Playgroud)

    但我想找到名叫Esther和Ruth AND Ada的妻子的男人.

  3. 哈哈,只是开玩笑,其实,我需要这个:我可以找到30岁以下名叫以斯帖的妻子

    @men = Man.has_young_wife_named('Esther')
    
    Run Code Online (Sandbox Code Playgroud)

    找到名叫Esther,Ruth或Ada的年轻妻子的男人

    @men = Man.has_young_wife_named(['Esther', 'Ruth', 'Ada'])
    
    Run Code Online (Sandbox Code Playgroud)

    但如上所述,我想找到名叫Esther和Ruth AND Ada的年轻妻子的男人.幸运的是,在这种情况下,最小值是固定的,但是指定最小年龄也是很好的.

  4. 有没有一种方法来测试用哈希语法的不平等,或者你总是要恢复到:conditions => ["", n]-注意之间的差异has_young_wife_namedhas_yw_named_v2-我喜欢的第一个更好的,但范围只适用于有限值.如果你正在寻找一位老太太,我想你可以使用a..100但是当妻子年满101岁时,她会放弃搜索.(嗯.她可以做饭吗?j/k)

  5. 有没有办法在范围内使用范围?我喜欢它,如果:has_red_cat可以:has_cat_of_color某种方式使用,或者如果有一些方法来使用其父级中的子记录的范围,那么我可以将与猫相关的范围放入Wife模型中.

我真的不想在没有使用的情况下在直接SQL中执行此操作named_scope,除非有其他更好的东西 - 插件的建议和诸如此内容非常感谢,或指向我需要学习的SQL类型.一位朋友建议UNIONs或子搜索在这里工作,但在Rails的上下文中似乎没有多少讨论.我对视图一无所知 - 它们会有用吗?是否有一种铁路开心的方式来制作它们?

谢谢!

当我去圣艾夫斯时,
我遇到了一个有七个妻子的男人
每个妻子有七个麻袋
每个麻袋有七只猫
每只猫有七个套装
套装,猫,麻袋,妻子
有多少人要去圣艾夫斯?

ste*_*com 2

嗯,我已经取得了很好的结果,named_scope如下所示:

named_scope :has_cat_older_than   lambda { |a| { :conditions => ["men.id in ( select man_id from wives where wives.id in ( select wife_id from cats where age > ? ) )", a] } }
Run Code Online (Sandbox Code Playgroud)

named_scope :has_young_wife_named lambda { |n| { :conditions => ["men.id in ( select man_id from wives where name = ? and age < 30)", n] } }
Run Code Online (Sandbox Code Playgroud)

我现在可以成功地做到

Member.has_cat_older_than(6).has_young_wife_named('Miriam').has_young_wife_named('Vashti')
Run Code Online (Sandbox Code Playgroud)

并得到我所期待的。这些范围不需要使用连接,并且它们似乎与其他样式的连接配合得很好。

哇!

评论引发了关于这是否是一种有效的方法,或者是否有更“rails-y”的方法的评论。将另一个模型的范围包含为 sql 子查询片段的某种方法可能会很有用......