I'm trying to query a table, listings, based on a has_many relationship with listing_options. Listing options have different types and I'd like to make a SQL query that can match listings with listing_options. Here's the SQL query atm:
SELECT "listings".* FROM "listings" INNER JOIN "listing_options" ON
"listing_options"."listing_id" = "listings"."id" WHERE ("listings".state IS NULL) AND
(listing_options.option_id IN ('1','2')) AND
(listing_options.option_id IN ('4','5','7')) LIMIT 12 OFFSET 0
Let's say I have two listings, with option values (1,5) and (1,6), respectively. I expect the query to return the first listing but not the second. The trouble is the query considers only one option value at a time, i.e. a option value can't be both 1 and 5, thus the query returns empty.
ActiveRecord to generate the SQL:
Listing.joins(:listing_options).where("listing_options.option_id IN (?)", [1,2]).where("listing_options.option_id IN (?)", [4,5,7])
Note: structuring the query like this results in duplicate records being returned if one part of the query is omitted, which may be part of the issue.
Same query with includes (also no results returned):
Listing.includes(:listing_options).where("listing_options.option_id IN (?)", [1,2]).references(:listing_options).where("listing_options.option_id IN (?)", [4,5,7])
class Listing
has_many :listing_options
has_and_belongs_to_many :options, join_table: :listing_options
class Option
belongs_to :option_type, inverse_of: :option
I've tried inversing the query to no avail (although doing it this way would also be more complicated as I would need to specify the option_ids to avoid based on option types).
Example:
Listing.includes(:listing_options).where("listing_options.option_id NOT IN (?)", [3,6,8]).references(:listing_options)
This query returns listings - more than it should. The query should be reasonably efficient for large numbers of listings and up to four types of listing options (additional queries on listing options). For this reason I want to do just one query rather than repetitively querying results.
edit - Solution - SQL from @ErwinBrandstetter written as search scope
.where('EXISTS (SELECT 1 FROM listing_options o1 JOIN listing_options o2 USING (listing_id) WHERE o1.listing_id = id AND o1.option_id IN (?) AND o2.option_id IN (?))', [1,2], [4,5,7])