Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Abfrageschnittpunkt mit aktivem Datensatz

Ihre Frage ist wahrscheinlich ohne Schnittmenge lösbar, etwa so:

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

Das Folgende ist jedoch ein allgemeiner Ansatz, den ich zum Erstellen von Abfragen wie Schnittmengen in ActiveRecord verwende:

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'))

Es generiert SQL der Form:

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

Sie können mit dem obigen Ansatz so viele Unterabfragen wie erforderlich erstellen, basierend auf beliebigen Bedingungen/Verknüpfungen usw., solange jede Unterabfrage die ID einer übereinstimmenden Person in ihrer Ergebnismenge zurückgibt.

Jede Unterabfrage-Ergebnismenge wird UND-verknüpft, wodurch die übereinstimmende Menge auf die Schnittmenge aller Unterabfragen beschränkt wird.

AKTUALISIEREN

Für diejenigen, die AR4 verwenden, wobei scoped entfernt wurde, liefert meine andere Antwort einen semantisch äquivalenten scoped polyfil welche all ist kein äquivalenter Ersatz für trotz allem, was die AR-Dokumentation vorschlägt. Antworten Sie hier:Mit Rails 4 ist Model.scoped veraltet, aber Model.all kann es nicht ersetzen