代码之家  ›  专栏  ›  技术社区  ›  Mitch Dempsey

如何选择子级不存在的记录

  •  4
  • Mitch Dempsey  · 技术社区  · 14 年前

    在rails中,我有两个表:

    bans(ban_id, admin_id)
    ban_reasons(ban_reason_id, ban_id, reason_id)
    

    我要找到所有的 bans 对于某个在 ban_reasons 桌子。在Rails中如何做到这一点,而不必遍历所有的ban记录并过滤掉所有带有 ban.ban_reasons.nil? 我希望使用一条SQL语句来实现这一点。

    SELECT bans.* FROM bans WHERE admin_id=1234 AND 
                                  ban_id NOT IN (SELECT ban_id FROM ban_reasons)
    
    3 回复  |  直到 14 年前
        1
  •  2
  •   Yannis    14 年前

    您的解决方案工作得很好(只有一个请求),但它几乎是纯SQL:

    bans = Ban.where("bans.id NOT IN (SELECT ban_id from ban_reason)")
    

    您也可以尝试以下方法,让rails完成部分工作:

    bans = Ban.where("bans.id NOT IN (?)", BanReason.select(:ban_id).map(&:ban_id).uniq)
    
        2
  •  2
  •   Maxem    14 年前

    ActiveRecord只会让您了解一点,之后的一切都应该由原始SQL完成。AR的好处是它使得做这类事情非常容易。

    然而,自从Rails3以来,您几乎可以用ARELAPI做任何事情,尽管原始SQL看起来可能更可读,也可能不可读。

    我将使用原始SQL,如果您的查询性能不好,您可以尝试另一个查询:

    SELECT       b.* 
    FROM         bans b
    LEFT JOIN    ban_reason br on b.ban_id = br.ban_id
    WHERE        br.ban_reason_id IS NULL
    
        3
  •  0
  •   EugZol Sandeep Jain    9 年前

    使用 Where Exists gem(我是这本书的作者):

    Ban.where(admin_id: 123).where_not_exists(:ban_reasons)