Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Interseção de consulta com registro ativo


Sua pergunta provavelmente é solucionável sem interseção, algo como:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
   people: :id).having('COUNT("people"."id")=2')

No entanto, o seguinte é uma abordagem geral que uso para construir consultas como interseções no ActiveRecord:
class Service < ActiveRecord::Base
  belongs_to :person

  def self.with_types(*types)
    where(service_type: types)
  end
end

class City < ActiveRecord::Base
  has_and_belongs_to_many :services
  has_many :people, inverse_of: :city
end

class Person < ActiveRecord::Base
  belongs_to :city, inverse_of: :people

  def self.with_cities(cities)
    where(city_id: cities)
  end

  def self.with_all_service_types(*types)
    types.map { |t|
      joins(:services).merge(Service.with_types t).select(:id)
    }.reduce(scoped) { |scope, subquery|
      scope.where(id: subquery)
    }
  end
end

Person.with_all_service_types(1, 2)
Person.with_all_service_types(1, 2).with_cities(City.where(name: 'Gold Coast'))

Ele irá gerar SQL da forma:
SELECT "people".*
  FROM "people"
 WHERE "people"."id" in (SELECT "people"."id" FROM ...)
   AND "people"."id" in (SELECT ...)
   AND ...

Você pode criar quantas subconsultas forem necessárias com a abordagem acima com base em quaisquer condições/junções etc., desde que cada subconsulta retorne o id de uma pessoa correspondente em seu conjunto de resultados.

Cada conjunto de resultados de subconsulta será combinado com AND, restringindo assim o conjunto correspondente à interseção de todas as subconsultas.

ATUALIZAÇÃO

Para aqueles que usam AR4 onde scoped foi removido, minha outra resposta fornece um scoped semanticamente equivalente polyfil que all não é um substituto equivalente, apesar do que a documentação do AR sugere. Responda aqui:Com Rails 4, Model.scoped está obsoleto, mas Model.all não pode substituí-lo