sql >> Database >  >> RDS >> Mysql

Doorsnede zoeken met activerecord

Uw vraag is waarschijnlijk oplosbaar zonder snijpunt, zoiets als:

Person.joins(:services).where(services: {service_type: [1,2]}).group(
   people: :id).having('COUNT("people"."id")=2')

Het volgende is echter een algemene benadering die ik gebruik voor het construeren van intersectie-achtige query's in 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'))

Het genereert SQL van het formulier:

SELECT "people".*
  FROM "people"
 WHERE "people"."id" in (SELECT "people"."id" FROM ...)
   AND "people"."id" in (SELECT ...)
   AND ...

U kunt zoveel subquery's maken als nodig is met de bovenstaande aanpak op basis van alle voorwaarden/joins enz., zolang elke subquery de id van een overeenkomende persoon in zijn resultatenset retourneert.

Elke resultaatset voor subquery's wordt aan elkaar gekoppeld, waardoor de overeenkomende set wordt beperkt tot het snijpunt van alle subquery's.

UPDATE

Voor degenen die AR4 gebruiken waar scoped is verwijderd, biedt mijn andere antwoord een semantisch equivalent scoped polyfil die all is geen gelijkwaardige vervanging voor ondanks wat de AR-documentatie suggereert. Antwoord hier:Met Rails 4 is Model.scoped verouderd, maar kan Model.all het niet vervangen



  1. mysql is een array in meerdere kolommen

  2. mysqli_connect():(HY000/2002):Kan geen verbinding maken met de lokale MySQL-server via socket

  3. LAST_INSERT_ID() is ongelijk aan $db->insert_id?

  4. MySQL krijgt alleen algemene ROLLUP