MySQL Многие ко Многим Запросам. Является ли это возможным? - PullRequest
2 голосов
/ 11 сентября 2011

Вот моя проблема: у меня есть три таблицы, которые представляют отношения многие ко многим, которые выглядят следующим образом:

таблица продуктов
product_id
product_price и т. Д. (базовая информация одинакова для каждого продукта)

спецификации таблицы
spec_id
имя_спецификации

таблица products_specification
product_id
spec_id
content

Моя цель - выбрать товары по их спецификациям (как одним, так и несколькими), поэтому я использовал следующий запрос:

SELECT *
FROM products p
JOIN products_specifications ps ON ps.products_id = p.products_id
JOIN specifications s ON s.spec_id = ps.spec_id
WHERE s.spec_name IN (<names of specs>)
AND pts.content IN (<content of specs>)
GROUP BY p.products_id
HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
AND COUNT(DISTINCT ps.content) = <count of specs content>

Iхотел бы получить ВСЕ спецификации, которые принадлежат ВСЕМ продуктам, однако этот запрос возвращает только одну из спецификаций (ту, которая используется для выполнения запроса).

В столбце Specification.content содержатся значения, которые яхотите использовать для запроса продукта (или нескольких) с (включены со всеми его спецификациями).Название этих спецификаций можно найти в таблице specs.name_name.Чтобы убедиться, что запрос не извлекает содержимое, которое, возможно, является таким же в другой строке, но из другой спецификации, я также делаю WHERE IN из названий спецификаций.

Возможно ли сделать запрос, который выбирает наопределенные спецификации, но также возвращает ВСЕ характеристики выбранного продукта?

Я думал и экспериментировал с UNIONS и SUBQUERIES.Однако я не смог произвести запрос, которого было достаточно.Я думаю, что подзапрос - это, вероятно, направление, в котором следует идти. Второй запрос с возвращенным product_id не является возможным, поскольку должна быть возможность заказать запрос ЛЮБОЙ из спецификаций, принадлежащих каждому продукту.

Ответы [ 4 ]

0 голосов
/ 12 сентября 2011

С твоим разъяснением, Рубен, я понимаю структуру базы данных и то, что ты сейчас спрашиваешь.Я начну с наблюдения, что вам нужно использовать для запроса к базе данных одну или несколько пар спецификаций.spec_name и products_specifications.content.Как вы указали в своем вопросе, вы хотите иметь возможность использовать один или несколько из них для запроса набора продуктов, который удовлетворяет всем условиям.

Чтобы понять, почему используется только попарное сочетание spec_name и contentРазумно, рассмотрим пример, в котором продукты представляют собой автомобили, а некоторые характеристики представляют собой цвета различных компонентов (например, body_color, interior_color, racing_stripe_color).Если вы ищете автомобили с красным цветом кузова и черным цветом салона, но запрос не связывает имя_спецификации и содержимое попарно, то вы также получите автомобили с черным цветом кузова и красным цветом салона, что вам не подходит.То же самое применимо, если в какой-либо из ваших спецификаций есть числа в качестве значений.

Мой ответ использует подзапрос для возврата значений product_id, которые будут использоваться для генерации окончательного вывода, но это также можно сделать с помощью дополнительных объединений.Если запрос, использующий подзапрос, слишком медленный, возможно, вам придется попробовать другую версию.Я также собираюсь использовать «select *», хотя я настоятельно рекомендую не делать этого в производственной среде (вместо этого вы должны перечислить столбцы), так как вещи имеют тенденцию ломаться намного легче, если есть изменения в структуре базы данных.,Вы также получите некоторые столбцы с дублирующимися значениями, которые могут быть устранены путем правильного перечисления столбцов.Я предполагаю, что product_id и spec_id уникальны в таблицах продуктов и спецификаций, соответственно, и что каждая комбинация product_id и spec_id встречается не более одного раза в таблице products_specifications.

select * from (
    select p1.product_id as product_id from products as p1
    join products_specifications as ps1 on p1.product_id = ps1.product_id
    join specifications as s1 on ps1.spec_id = s1.spec_id
    where <selection conditions>
    group by p1.product_id
    having count(s1.spec_id) = <number of selection conditions>
    ) pp 
join products as p on pp.product_id = p.product_id
join products_specifications as ps on p.product_id = ps.product_id
join specifications as s on ps.spec_id = s.spec_id
order by p.product_id, s.spec_name;

будет иметь вид:

   (s1.spec_name = 'spec1' and ps1.content = 'spec1value')
or (s1.spec_name = 'spec2' and ps1.content = 'spec2value')
or ...

для столько пар spec_name, сколько вы хотите использовать в запросе.Вам нужно будет сгенерировать эту часть запроса вручную или в коде вызова.Вам нужно убедиться, чторавняется количеству условий таким же образом.

0 голосов
/ 11 сентября 2011

Мне не совсем ясно, что вы пытаетесь сделать, но если я могу переформулировать вашу цель: вы хотели бы выбрать «продукты» с заданной «спецификацией», но для этих «продуктов» выберите все их «спецификации». ». Вы дважды пытались объединить таблицы «products_specifications» и «specification» следующим образом:

SELECT * 
FROM products p
JOIN product_specifications ps1 ON ps1.products_id = p.products_id
JOIN specifications s1 ON s1.spec_id = ps1.spec_id
JOIN product_specifications ps2 ON ps2.products_id = p.products_id
JOIN specifications s2 ON s2.spec_id = ps2.spec_id
WHERE s.spec_name IN (<names of specs>)
AND pts.content IN (<content of specs>)
GROUP BY p.products_id
HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
AND COUNT(DISTINCT pts.content) = <count of specs content>

Обратите внимание на s1 & s2 и ps1 & ps2. S1 & ps1 позволит вам выбрать, но вы можете увидеть все, используя s2 & ps2. Также в вашем предложении WHERE было указано pts, но вы не указали его в виде таблицы в разделе FROM. Полагаю, вы подразумевали ps?

0 голосов
/ 11 сентября 2011

Ваш запрос кажется правильным. Он вернет детали всех продуктов для тех продуктов, которые соответствуют вашим критериям (они действительны для всех (<names of specs>) и всех (<content of specs>)). Кстати, было бы лучше использовать SELECT p.*, поскольку вы группируете по p.products_id. Результаты, полученные из других столбцов, не очень полезны.

Теперь, если вы хотите получить эти продукты и, кроме того, получить все спецификации для этих продуктов (не только spcs, которые есть в ваших двух списках), используйте это:

( обновление: Добавлено GROUP BY pd.products_id и GROUP_CONCAT() для сбора информации о продукте из множества строк в одну)

SELECT pd.*
     , GROUP_CONCAT( ps.content
                     ORDER BY ps.spec_id )
     , GROUP_CONCAT( s.spec_name 
                     ORDER BY ps.spec_id )
     , GROUP_CONCAT( CONCAT(s.spec_name,'-',ps.content)
                     ORDER BY ps.spec_id )
FROM
    ( SELECT p.*
      FROM products p
      JOIN products_specifications ps ON ps.products_id = p.products_id
      JOIN specifications s ON s.spec_id = ps.spec_id
      WHERE s.spec_name IN (<names of specs>)
      AND ps.content IN (<content of specs>)
      GROUP BY p.products_id
      HAVING COUNT(DISTINCT s.specifications_name) = <count of specs name>
      AND COUNT(DISTINCT ps.content) = <count of specs content>
    ) AS pd
  JOIN
    products_specifications ps ON ps.products_id = pd.products_id
  JOIN
    specifications s ON s.spec_id = ps.spec_id  
GROUP BY pd.products_id
0 голосов
/ 11 сентября 2011
SELECT *
FROM products_specifications
GROUP BY product_id;
...