Я хочу сделать SQL-запрос, чтобы получить отдельные данные о продуктах, имеющих атрибуты в отдельной таблице - PullRequest
0 голосов
/ 11 мая 2018

У меня есть таблицы:

  1. Продукты (id, title)

[1, «Старая машина»], [2, «Новая машина»], [3, «Машина будущего»])

  1. Атрибуты (идентификатор, имя)

[1, «бренд»], [2, «модель»], [3, «цвет»]

  1. Attribute_values ​​(attribute_id, product_id, value)

[1, 1, «Тойота»], [1, 2, «Хонда»], [1, 3, «Форд»], [1, 3, «красный»], [2, 3, «белый» '], [3, 3,' красный ']

Я пробовал запрос:

select p.*, a.name as attribute_name, av.value as attribute_value from attributes as a 
join attribute_values as av on a.id=av.attribute_id
join products as p on av.product_id=p.id
where
((a.name='brand' and av.value='toyota') or (a.name='color' and av.value='red'))

Это дает каждой строке, соответствующей условию или запросу.

Например:

  • [id: 1, title: 'Old car', имя_атрибута: 'brand', ATTRIBUTE_VALUE: 'Тойота']
  • [id: 1, title: 'Old car', имя_атрибута: 'color', ATTRIBUTE_VALUE: 'красный']
  • [id: 3, title: 'Future car', имя_атрибута: 'color', ATTRIBUTE_VALUE: 'красный']

Здесь найдены следующие результаты: «Старый автомобиль» и «Автомобиль будущего», но мне нужно «Старый автомобиль», а не «Автомобиль будущего».

Можно ли это сделать одним запросом?

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Вы можете попробовать этот запрос.Исходный запрос выводит 1 строку, когда записи соответствуют 1 вашему критерию.По результату мы проверяем тот же product id, есть ли в результатах 2 записи.Если да, то это означает, что 2 критерия (марка = Toyota & цвет = red) совпадают для одного и того же product.

SELECT id as product_id, count(attribute_name) as attribute_count FROM
(
    select 
        p.*, 
        a.name as attribute_name, 
        av.value as attribute_value

    from products as p 
        join attribute_values as av
            on p.id = av.product_id
        join attributes as a 
            on a.id = av.attribute_id

    where
        (a.name='brand' and av.value='toyota')
        or (a.name='color' and av.value='red')

) a

GROUP BY a.id
HAVING (attribute_count = 2);

Ссылка SQL Fiddle для теста: http://sqlfiddle.com/#!9/ab857a/2

Редактировать:

С другой стороны, вы также можете попробовать это second approach.Сначала мы делаем 2 отдельных subselect, чтобы получить продукт, который соответствует каждому из 2 критериев.Затем мы JOIN подразделяемся вместе, чтобы получить продукты, соответствующие обоим критериям:

SELECT
    a.*,
    b.attribute_2,
    b.value_2

FROM
(
    SELECT 
        p.*, 
        a.name as attribute_1, 
        av.value as value_1
    FROM
        products as p
        JOIN attribute_values as av 
            ON av.product_id = p.id
        JOIN attributes as a
            ON a.id = av.attribute_id
    WHERE
        a.name = 'brand'
        and av.value = 'toyota'
) a

JOIN

(
    SELECT 
        p.*, 
        a.name as attribute_2, 
        av.value as value_2
    FROM
        products as p
        JOIN attribute_values as av 
            ON av.product_id = p.id
        JOIN attributes as a
            ON a.id = av.attribute_id
    WHERE
        a.name = 'color'
        and av.value = 'red'
) b

ON a.id = b.id

Пример кода SQL Fiddle здесь: http://sqlfiddle.com/#!9/8b836d/1

0 голосов
/ 11 мая 2018

Я изменил записи в вашей таблице attribute_value следующим образом, предполагая, что это правильно:

attribute_id  |   product_id   |   value
------------------------------------------
1         |       1        |   toyota
1         |       2        |   honda
1         |       3        |   ford
3         |       1        |   red
3         |       2        |   white
3         |       3        |   red

и я изменил ваш запрос следующим образом:

select p.*, a.name as attribute_name, av.value as attribute_value from attributes as a 
    join attribute_values as av on a.id=av.attribute_id
    join products as p on av.product_id=p.id
    where
        (
            if(a.name='brand',av.value='toyota',0) 
      or if(a.name='color',av.value='red',0)
     ) 
GROUP BY p.id HAVING COUNT(av.attribute_id) =2

Здесь "2" должно быть динамическим в зависимости от того, сколько атрибутов вы фильтруете. Так как в вашем примере вы фильтровали с 2 атрибутами, я упомянул 2

Скрипка присутствует по адресу: http://sqlfiddle.com/#!9/b6ff9/2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...