【问题标题】:Querying a record with a many-to-many relationship based on whether or not it has certain corresponding records根据是否有一定的对应记录查询多对多关系的记录
【发布时间】:2014-02-08 02:01:34
【问题描述】:

此应用在 Rails 4 和 Ruby 2 上运行。

我有两个模型,Key 和 Chord,它们具有多对多关系through: Keychords

Keychord 有两个字段:key_idchord_id

我想运行一个查询,该查询返回在给定的和弦数组中具有每个和弦的所有键。

例如

key1 与和弦相关,ID 为:[1, 2, 3, 4]

key2 与和弦相关,ID 为:[1, 3, 4, 6]

key3 与和弦相关,ID 为:[2, 3, 5, 6]

key4 与和弦相关,ID 为:[1, 3, 4, 5]

如果我有一个 Chord ID 数组:[2, 3]

我希望查询返回[key1, key3]


我想要但不知道如何实际编写的伪代码:

Key.with(:chords, [2,3])

谢谢!

【问题讨论】:

    标签: sql ruby-on-rails ruby


    【解决方案1】:

    试试:

    class Key < ActiveRecord::Base
      scope :with_chords, ->(chords) { joins(:keychords).where(keychords: {chord_id: chords}).group("#{table_name}.#{primary_key}").having('COUNT(DISTINCT keychords.chord) = ?', chords.size)
    end
    
    Key.with_chords([2,3])
    

    更新 - 解释:

    这实际上很 hacky,但到目前为止我还没有看到更好的解决方案。 例如,假设我们有表:

    #Table A   |   #Table B
      id       |     id         a_id     key_id
    ---------------------------------------------------   
      1        |     1            1        2
      2        |     2            3        3
      3        |     3            3        2
      4        |     4            4        1
      5        |     5            2        3
               |     6            4        2
    

    我们正在从 A 中寻找与 key_ids 2 和 3 相关联的元素。

    第一步是与关联表执行连接。作为连接的结果,查询将返回 n 行记录,该记录在第二个表中具有 n 个关联行。它看起来像这样:

     a.id     b.id    b.a_id    b.key_id
    --------------------------------------
      1        1        1          2
      2        5        2          3   
      3        2        3          3
      3        3        3          2
      4        4        4          1
      4        6        4          2
    

    请注意,没有关联的A 记录根本不会返回。 下一步是过滤这些行并只取那些我们正在寻找的关联(2 OR 3)这是由where方法完成的。结果:

     a.id     b.id    b.a_id    b.key_id
    --------------------------------------
      1        1        1          2
      2        5        2          3   
      3        2        3          3
      3        3        3          2
      4        6        4          2
    

    下一步是按a.id 对其进行分组。与分组一起,我们将添加having语句,它将计算b.key_id的所有不同值并拒绝那些小于初始ID列表的组。这确保我们返回的记录具有所有提供的键。

      a.id | COUNT(DISTINCT b.key_id)
    -----------------
      1    |    1    
      2    |    1  
      3    |    2      # The only result
      4    |    1
    

    【讨论】:

    • 谢谢,现在测试一下。澄清一下,我应该将其保留为“#{table_name}.#{primary_key}”还是 table_nameprimary_key 占位符?另外,我认为您缺少结束语}。这应该排在最后吗?
    • 您是否愿意快速解释一下上述每个查询的实际工作原理?
    • 哇,感谢您花时间解释这一点。非常感谢!
    • 我知道你已经很久没有回答这个问题了,但我希望你能回答我的后续问题。您将如何修改上述查询以仅返回恰好具有和弦 [2, 3] 而不是在其他和弦中具有和弦 [2, 3] 的键?非常感谢!
    • @jackerman09 - 上面的语句应该已经这样做了。 having 语句将拒绝匹配超过 2 个的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    相关资源
    最近更新 更多