Mysql question: is there something like IN ALL query?
For example this query:
SELECT `variants`.*
FROM `variants` INNER JOIN `variant_attributes`
ON variant_attributes.variant_id = variants.id
WHERE (variant_attributes.id开发者_如何学Python IN ('2','5'))
And variant has_many variant_attributes
What I actually want to do is to find which variant has BOTH variant attributes with ID = 2 and 5. Is this possible with MySQL? Bonus Question, is there a quick way to do this with Ruby on Rails, perhaps with SearchLogic?
solution
Thank you Quassnoi for the query you provided, that worked perfectly.
To use on Rails, I used the named_scope below, I think this is simpler to understand for beginners.
Basically named_scope would return {:from => x, :conditions => y} and the lines above were used to setup the y variable.
named_scope :with_variant_attribute_values, lambda { |values|
conditions = ["(
SELECT COUNT(*)
FROM `variant_attributes`
WHERE variant_attributes.variant_id = variants.id
AND variant_attributes.value IN (#{values.collect { |value| "?" }.join ", "})
) = ?
"]
conditions = conditions + values + [values.length]
{
:from => 'variants',
:conditions => conditions
}}
Assiuming that variant_attributes (variant_id, id)
is unique:
SELECT `variants`.*
FROM `variants`
WHERE (
SELECT COUNT(*)
FROM `variant_attributes`
WHERE variant_attributes.variant_id = variants.id
AND variant_attributes.id IN ('2','5')
) = 2
Quassnoi has posted the mysql query that does what you would like. Here is a method for the Variant
model that will do the equivalent. I'm doing two approaches, one if variant_attributes (variant_id, id)
are a unique combination, and one if they aren't
Unique:
class Variant < ActiveRecord::Base
has_many :variant_attributes
named_scope :with_variant_attributes, lamda { |*ids|
ids = ids.flatten
if(ids.length>0)
result = {:include => :variant_attributes}
sql_params = {:length => ids.length,:ids => ids}
result[:conditions] = ["(:length = (select count(*) from variant_attributes
where id in (:ids))",sql_params]
result
else
nil
end
}
end
Non Unique
class Variant < ActiveRecord::Base
has_many :variant_attributes
named_scope :with_variant_attributes, lamda { |*ids|
ids = ids.flatten
if(ids.length>0)
result = {:include => :variant_attributes}
conditions = []
sql_params = {}
ids.each_with_index do |id,i|
conditions << "( 1 = Select Count(*) from variant_attributes where id = :id#{i})"
sql_params["id#{i}"] = id
end
result[:conditions] = [ '(' + conditions.join(' AND ') + ')', sql_params]
result
else
nil
end
}
end
Which can be used in the following ways:
# Returns all Variants with variant_attributes 1, 2, & 3
vars = Variant.with_variant_attributes(1,2,3)
# Returns Variant 5 if it has attributes 3 & 5, or null if it doesn't
vars = Variant.with_variant_attributes(3,5).find_by_id(5)
#Returns Variants between 1 and 20 if that have an attribute of 2
vars = Variant.with_variant_attributes(2).find(:conditions => "id between 1 and 20")
#can accept a variable array of ids
my_ids = [3,5]
vars = Variant.with_variant_attributes(my_ids)
This code hasn't been tested.
I would create a named_scope for this:
class Variant < ActiveRecord::Base
has_many :variant_attributes
named_scope :with_variant_attributes, lambda { |*ids| {
:joins => :variant_attributes,
:conditions => {:variant_attributes=>{:id=>ids}},
:group => "variants.id",
:having => "count(variants.id) = #{ids.size}"
}
}
end
Now you can use the named scope as follows:
Variant.with_variant_attributes(1,2)
Variant.with_variant_attributes(1,2,3,4)
Thank you Quassnoi for the query you provided, that worked perfectly.
To use on Rails, I used the named_scope below, I think this is simpler to understand for beginners.
Basically named_scope would return {:from => x, :conditions => y} and the lines above were used to setup the y variable.
named_scope :with_variant_attribute_values, lambda { |values|
conditions = ["(
SELECT COUNT(*)
FROM `variant_attributes`
WHERE variant_attributes.variant_id = variants.id
AND variant_attributes.value IN (#{values.collect { |value| "?" }.join ", "})
) = ?
"]
conditions = conditions + values + [values.length]
{
:from => 'variants',
:conditions => conditions
}}
精彩评论