Rails:在HABTM关系中查找没有连接的行

时间:2014-02-26 21:38:07

标签: ruby-on-rails ruby has-and-belongs-to-many

我有两个模型,UsersLeads与HABTM关系相关:

class Lead < ActiveRecord::Base
  has_and_belongs_to_many :users
end

class User < ActiveRecord::Base
  has_and_belongs_to_many :leads
end

我现在如何才能获得那些未与用户连接的潜在顾客?

提前致谢!

3 个答案:

答案 0 :(得分:9)

您正在寻找的内容称为 anti join

有三种标准方法可以实现这一目标,

  1. 使用null左外连接
  2. 将where子句与带有NOT&amp;的子查询一起使用IN个关键字
  3. 将where子句与NOT&amp; EXISTS个关键字
  4. 基本上,EXISTS关键字将检查子查询是否返回任何行并报告为匹配,NOT显然否定了该匹配。

    这是我的首选方式(使用NOT&amp; EXISTS

    class User < ActiveRecord::Base
      has_and_belongs_to_many :leads
      def self.without_leads
        where(<<-SQL)
          NOT EXISTS (SELECT 1 
            FROM   leads_users 
            WHERE  users.id = leads_users.user_id) 
        SQL
      end
    end
    
    class Lead < ActiveRecord::Base
      has_and_belongs_to_many :users
      def self.without_users
        where(<<-SQL)
          NOT EXISTS (SELECT 1 
            FROM   leads_users 
            WHERE  leads.id = leads_users.lead_id) 
        SQL
      end
    
     def self.not_connected_to(user)
        where(<<-SQL, user.id)
          NOT EXISTS (SELECT 1 
            FROM   leads_users 
            WHERE  leads.id = leads_users.lead_id
            AND leads_users.user_id = ?
            ) 
        SQL
      end
    end
    

    这是使用arel

    非SQL 方法
    class User < ActiveRecord::Base
      has_and_belongs_to_many :leads
      def self.without_leads
        habtm_table = Arel::Table.new(:leads_users)
        join_table_with_condition = habtm_table.project(habtm_table[:user_id])
        where(User.arel_table[:id].not_in(join_table_with_condition))
      end
    end
    
    class Lead < ActiveRecord::Base
      has_and_belongs_to_many :users
      def self.without_users
        habtm_table = Arel::Table.new(:leads_users)
        join_table_with_condition = habtm_table.project(habtm_table[:lead_id])
        where(Lead.arel_table[:id].not_in(join_table_with_condition))
      end
    end
    

    here is an example repo

    查找没有潜在客户的用户

    User.where(user_id: 1).without_leads
    

    查找没有用户的潜在客户

    Lead.without_users
    

    查找未与特定用户相关的潜在客户

    Lead.not_connected_to(user)
    

    链式排序

    Lead.without_users.order(:created_at)
    

答案 1 :(得分:3)

您可以使用左连接。假设您的联接表名为leads_users

Lead.joins('LEFT JOIN leads_users ON leads_users.lead_id = leads.id').
     where(leads_users: { user_id: nil })

答案 2 :(得分:0)

Kerozu,如果要显示仅不是当前用户购买的销售线索,则可以使用这样的原始sql

    sql = <<-SQL
      SELECT *
      FROM leads
      WHERE id NOT IN (
        SELECT lead_id
        FROM leads_users
        WHERE user_id = ?
      )
    SQL

    Lead.find_by_sql [sql, id]