Каков наилучший способ реализовать этот запрос SQL? - PullRequest
2 голосов
/ 29 июня 2009

У меня есть таблица PRODUCTS, и у каждого продукта может быть несколько атрибутов, поэтому у меня есть таблица ATTRIBUTES и еще одна таблица с именем ATTRIBPRODUCTS, которая находится посередине. Атрибуты сгруппированы по классам (тип, марка, материал, цвет и т. Д.), Поэтому людям может потребоваться продукт определенного типа от определенного бренда.

PRODUCTS
product_id
product_name

ATTRIBUTES
attribute_id
attribute_name
attribute_class

ATTRIBPRODUCTS
attribute_id
product_id

Когда кто-то ищет продукт, он может выбрать один или несколько атрибутов. У меня проблема с возвратом одного продукта, который имеет несколько атрибутов. Это должно быть очень просто, я знаю, но SQL на самом деле не мое, и после определенного момента я немного теряюсь в логике. Проблема в том, что я пытаюсь проверить каждый класс атрибутов отдельно, поэтому я хочу получить что-то вроде:

SELECT DISTINCT products.product_id
FROM         attribproducts 
INNER JOIN products ON attribproducts.product_id = products.product_id
WHERE     (attribproducts.attribute_id IN (9,10,11)
AND        attribproducts.attribute_id IN (60,61))

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

Кто-нибудь может немного помочь? К сожалению, я не могу позволить себе полную реорганизацию базы данных, в этом есть что-то большее, чем этот бит, поэтому любые предложения о том, как работать с тем, что у меня есть, будут с благодарностью приняты.

Ответы [ 6 ]

3 голосов
/ 29 июня 2009

Посмотрите на ответы на вопрос SQL: таблица «многие ко многим» И запрос . Это точно такая же проблема. Cletus дал там 2 возможных решения, ни одно из которых не было тривиальным (но опять же, просто нет тривиального решения).

1 голос
/ 29 июня 2009
SELECT DISTINCT products.product_id 
FROM products p
INNER JOIN attribproducts ptype on p.product_id = ptype.product_id
INNER JOIN attribproducts pbrand on p.product_id = pbrand.product_id 
WHERE ptype.attribute_id IN (9,10,11) 
    AND pbrand.attribute_id IN (60,61)
0 голосов
/ 29 июня 2009

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

select distinct product_id
from products p
inner join attribproducts a1 on a1.product_id=p.product_id
inner join attribproducts a2 on a1.product_id=p.product_id
where a1.attribute_id in (9,10,11) 
  and a2.attribute_id in (60,61)
0 голосов
/ 29 июня 2009

Похоже, у вас есть схема данных, которая БОЛЬШАЯ для хранения, но ужасна для выбора / создания отчетов. Если у вас есть структура данных OBJECT, ATTRIBUTE, OBJECT-ATTRIBUTE и OBJECT-ATTRIBUTE-VALUE, вы можете хранить множество объектов со многими различными атрибутами для каждого объекта. Это иногда называют «Вертикальным хранилищем».

Однако, если вы хотите получить список объектов со всеми значениями их атрибутов, это переменное число объединений, которые вы должны сделать. Получить данные намного проще, если они хранятся по горизонтали (определенные столбцы данных)

Я сталкивался с этим сценарием несколько раз. Поскольку вы не можете изменить существующую структуру данных. Я бы предложил написать «слой» таблиц сверху. Динамически создавайте таблицу для каждого имеющегося у вас объекта / продукта. Затем динамически создайте статические столбцы в этих новых таблицах для каждого атрибута. В значительной степени вам нужно «сгладить» ваш вертикально сохраненный атрибут / значения в статические столбцы. Преобразование из вертикальной архитектуры в горизонтальную.

Используйте «сплющенные» таблицы для отчетов и вертикальные таблицы для хранения.

Если вам нужен пример кода или более подробная информация, просто спросите меня.

Надеюсь, это понятно. У меня еще не было много кофе:)

Спасибо, - Марк

0 голосов
/ 29 июня 2009

Это не вернет ни одной строки, потому что вы учитываете только те строки, у которых есть число (либо 9, 10, 11) И (либо 60, 61).

Поскольку эти множества не пересекаются, вы не получите строк.

Если вместо этого вы используете ИЛИ, он даст продукты с атрибутами, которые находятся в наборе 9, 10, 11, 60, 61, что тоже не то, что вам нужно, хотя тогда вы получите несколько строк для каждого продукт.

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

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

0 голосов
/ 29 июня 2009

Попробуйте это:

select * from products p, attribproducts a1, attribproducts a2
  where p.product_id = a1.product_id
    and p.product_id = a2.product_id
    and a1.attribute_id in (9,10,11)
    and a2.attribute_id in (60,61);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...