2015-11-29 3 views
2

У меня есть три таблицы:SQL Filtering Комплексный запрос

ПРОДУКТА

PRODUCT_ID|NAME 
    1 |Elaborado 
    2 |Adidas 

PRODUCT_ATTRIBUTE

PRODUCT_ATTRIBUTE_ID|PRODUCT_ID|ATTRIBUTE_ID|VALUE 
     1   |1   |1   |Solid 
     2   |1   |2   |Casual 
     3   |2   |1   |Solid 

ATTRIBUTE

ATTRIBUTE_ID|DESCRIPTION 
     1 |Pattern 
     2 |Occasion 

Все атрибуты находятся в таблице ATTRIBUTE. Связь между продуктами и атрибутами находится в PRODUCT_ATTRIBUTE. Теперь мне нужно фильтровать продукты, основанные на атрибутах:

Для бывших: Я нужны продукты, чьи Паттерн «Solid» и повод «Casual»:

Результат должен быть, как показано ниже:

PRODUCT_ID 
---------- 
1 

Я использую базу данных Mysql. Я подготовил SQLFiddle: http://sqlfiddle.com/#!9/aa2be/3

Пожалуйста, помогите.

Thanks, Sash.

+0

Я хотел бы сделать псевдо нормализованы стержень и фильтр, что. Это не самый быстрый метод, но это самый простой способ подумать о смешении различных требований фильтрации. – Strawberry

ответ

0

Заканчивать этот

select group_concat(product.name),attribute.DESCRIPTION,product_attribute.value from product 
join product_attribute 
on (product_attribute.product_id=product.product_id) 
join attribute 
on (product_attribute.attribute_id=attribute.attribute_id) 
where (attribute.attribute_id = 1 and product_attribute.value = 'Solid') 
or 
(attribute.attribute_id = 2 and product_attribute.value = 'Casual') 
group by attribute.attribute_id, product_attribute.value 
0

Концепция хранения столбцов в виде строк называется Entity-Attribute-Value (EAV) и это делает для сложных запросов :) Например, вы могли бы найти «шаблон = твердый и случай = случайный», как:

select p.product_id 
from product p 
join product_attribute pa1 
on  p.product_id = pa1.product_id 
join attribute a1 
on  pa1.attribute_id = a1.attribute_id 
join product_attribute pa2 
on  p.product_id = pa2.product_id 
join attribute a2 
on  pa2.attribute_id = a2.attribute_id 
where a1.description = 'Pattern' 
     and pa1.value = 'Solid' 
     and a2.description = 'Occasion' 
     and pa2.value = 'Casual' 

Example at SQL Fiddle.

альтернативный подход заключается в создании повернута вид, как:

create view vw_product_attribute as 
select p.product_id 
,  pa_pattern.value as pattern 
,  pa_occasion.value as occasion 
from product p 
join product_attribute pa_pattern 
on  p.product_id = pa_pattern.product_id 
join attribute a_pattern 
on  pa_pattern.attribute_id = a_pattern.attribute_id 
join product_attribute pa_occasion 
on  p.product_id = pa_occasion.product_id 
join attribute a_occasion 
on  pa_occasion.attribute_id = a_occasion.attribute_id 
where a_pattern.description = 'Pattern' 
     and a_occasion.description = 'Occasion' 

Вы можете запросить как:

select product_id 
from vw_product_attribute 
where pattern = 'Solid' 
     and occasion = 'Casual' 

Example of the alternate approach at SQL Fiddle.

+0

Привет, спасибо, но что, если количество атрибутов фильтра является динамическим? –

+0

@sash: вы можете добавить все известные свойства в представление. Для переменной количества свойств вы должны создать пользовательский оператор SQL – Andomar

+0

Спасибо. Вы имеете в виду, что мне нужно генерировать так много соединений, динамически используя код? Могу ли я написать запрос, который работает для любого количества атрибутов? Является ли это возможным? Благодарю. –

0

Будет ли это работать для вас? Вам нужно будет установить описание и значение в подзапросе, в котором задана переменная patternSolidProduct, и инструкция SELECT.

Вы также должны указать индекс PK на attribute. attribute_id, product. product_id и product_attribute. product_attribute_id

Я добавил индексы к product_attribute. value с длиной 10, attribute. description с длиной 10.

/*Start join method */ 
/* Get product id's matching pattern = solid */ 
SET @patternSolidProduct := (SELECT 
    GROUP_CONCAT(`pa`.`product_id`) 
FROM 
    `product_attribute` AS `pa` 
LEFT JOIN 
    `product` as `p` 
ON 
    `pa`.`product_id` = `p`.`product_id` 
LEFT JOIN 
    `attribute` AS `a` 
ON 
    `a`.`attribute_id` = `pa`.`attribute_id` 
WHERE 
    `a`.`description` = 'Pattern' 
    AND `pa`.`value` = 'Solid' 
); 
/* End product id's matching pattern = solid */ 

SELECT 
    `pa`.`product_id` 
FROM 
    `product_attribute` AS `pa` 
LEFT JOIN 
    `product` as `p` 
ON 
    `pa`.`product_id` = `p`.`product_id` 
LEFT JOIN 
    `attribute` AS `a` 
ON 
    `a`.`attribute_id` = `pa`.`attribute_id` 
WHERE 
    `a`.`description` = 'Occasion' 
    AND `pa`.`value` = 'Casual' 
    AND `p`.`product_id` IN (@patternSolidProduct) 
/*End join method */ 

Explain, из сказанного выше:

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra 
'1', 'SIMPLE', 'p', 'const', 'PRIMARY', 'PRIMARY', '8', 'const', '1', 'Using index' 
'1', 'SIMPLE', 'pa', 'ref', 'value', 'value', '32', 'const', '1', 'Using where' 
'1', 'SIMPLE', 'a', 'eq_ref', 'PRIMARY,description', 'PRIMARY', '8', 'sqlfiddle.pa.attribute_id', '1', 'Using where' 
Смежные вопросы