Mysql вопрос: есть что-то вроде запроса ВСЕ? - PullRequest
1 голос
/ 30 апреля 2010

Например, этот запрос:

SELECT `variants`.* 
  FROM `variants` INNER JOIN `variant_attributes` 
    ON variant_attributes.variant_id = variants.id 
 WHERE (variant_attributes.id IN ('2','5'))

И вариант имеет_ множество вариантов_атрибутов

Что я на самом деле хочу сделать, так это выяснить, какой вариант имеет ОБА атрибуты варианта с ИД = 2 и 5. Возможно ли это с MySQL? Бонусный вопрос, есть ли быстрый способ сделать это с Ruby on Rails, возможно, с SearchLogic?

решение

Спасибо, Quassnoi, за предоставленный вами запрос, который отлично работал.

Чтобы использовать в Rails, я использовал named_scope ниже, я думаю, что это проще для начинающих.

В основном named_scope вернул бы {: from => x,: условие => y}, а строки выше были использованы для установки переменной y.

  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
  }}

Ответы [ 4 ]

3 голосов
/ 30 апреля 2010

Предполагая, что variant_attributes (variant_id, id) уникален:

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
1 голос
/ 30 апреля 2010

Quassnoi опубликовал запрос MySQL, который делает то, что вы хотите. Вот метод для модели Variant, который сделает эквивалент. Я делаю два подхода, один, если variant_attributes (variant_id, id) уникальная комбинация, и один, если они не

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

Не уникален

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

Который может использоваться следующими способами:

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

Этот код не был проверен.

0 голосов
/ 09 мая 2010

Спасибо, Quassnoi, за предоставленный вами запрос, который отлично работал.

Чтобы использовать на Rails, я использовал named_scope ниже, я думаю, что это проще для начинающих.

В основном named_scope будет возвращать {: from => x,: условие => y}, а строки выше были использованы для установки переменной y.

  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
  }}
0 голосов
/ 01 мая 2010

Я бы создал named_scope для этого:

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

Теперь вы можете использовать именованную область следующим образом:

Variant.with_variant_attributes(1,2)
Variant.with_variant_attributes(1,2,3,4)
...