Как выбрать строки из таблицы MySQL, сгруппированные по одному столбцу с необходимыми значениями в другом - PullRequest
2 голосов
/ 01 апреля 2009

Мне нужно отфильтровать продукты, в которых определенные атрибуты хранятся в объединенной таблице, которая соответствует всем требуемым свойствам, то есть пользователи должны иметь возможность постепенно сузить свой поиск, добавив требования.

Проблема действительно касается таблицы свойств, я думаю, а не объединения, учитывая следующую (упрощенную) таблицу свойств продукта:

id  product_id  property  value
---------------------------------
1   1           color     red
2   1           size      small
3   2           color     red
4   2           size      large

как мне получить все product_ids, где значение имеет значение 'red' и 'small'?

Подобный вопрос был задан ранее, но не был дан очень полный ответ. Решение включает в себя COUNT и HAVING, чтобы получить строки, где в каждой группе столько строк, сколько требуется, например,

SELECT product_id, count(*) AS group_count FROM properties where
value = 'red' OR value = 'small'
GROUP BY product_id
HAVING group_count = 2

Это работает, но я беспокоюсь о производительности, кажется, что был бы лучший способ.

В конце концов к этому нужно будет присоединиться или хотя бы использовать его для фильтрации таблицы продуктов:

id  name     
-------------
1   Product 1
2   Product 2

Я забыл упомянуть, что у меня есть две из этих таблиц свойств, связанных с продуктами, по которым мне нужно фильтровать, одна с обычными атрибутами продукта, другая с доступными настраиваемыми параметрами (немного похоже на варианты). Сценарий состоит в том, чтобы позволить пользователям фильтровать такие продукты, как: «показать продукты, где пол =« мужской », бренд =« nike »и размер ==« маленький »», где пол и бренд - это «свойства», а размер - в настройках (настраивается при добавлении в корзину)

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

Я мог бы просто получить идентификаторы из свойств (и другой таблицы), а затем просто сделать выбор, где id IN (идентификаторы), соответствующие набору идентификаторов для обеих таблиц свойств, мне не нравится идея сделать это с хотя действительно длинный список идентификаторов.

Ответы [ 4 ]

2 голосов
/ 01 апреля 2009
SELECT DISTINCT p1.product_id, pn.name 
FROM properties p1, properties p2,
     productNames pn
WHERE p1.product_id = p2.product_id
AND p1.property = 'size' and value = 'small'
AND p2.property = 'color' and value = 'red'
AND pn.id = p1.product_id
2 голосов
/ 01 апреля 2009

Не уверен, что это быстрее, но соединения из подзапросов, сгенерированных по вашим критериям фильтра, будут работать:

Select p.name, p.id from product p, 
(select product_id from properties where value='red') colors,
(select product_id from properties where value='small') sizes
where p.id=colors.product_id and p.id=sizes.product_id
1 голос
/ 02 апреля 2009

Еще одно столкновение с одной из ловушек модели данных атрибута-значения.

Предполагая, что вам нужны продукты, в которых «цвет» соответствует «красному», а «размер» соответствует «маленькому» (вы не говорите, что свойство действительно имеет значение, только значение), большую часть вопрос в том, как вы представляете список требуемых совпадений? Будут ли они передаваться в виде строки с разделителями, храниться во временной таблице, динамически создаваемый SQL, что-то еще?

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

SELECT
    P.*
FROM
    Products P
WHERE
    NOT EXISTS
    (
        SELECT
            *
        FROM
            Product_Search_Template PST
        LEFT OUTER JOIN Properties P2 ON
            P2.property = PST.property AND
            P2.value = PST.value AND
            P2.product_id = P.product_id
        WHERE
            P2.id IS NULL
    )

.

SELECT
    P.*
FROM
(
    SELECT
        PROP1.product_id,
        COUNT(*) AS match_count
    FROM
        Properties PROP1
    INNER JOIN Product_Search_Template PST ON
        PST.property = PROP1.property AND
        PST.value = PROP1.value
    GROUP BY
        PROP1.product_id
) SQ
INNER JOIN Products P ON
    P.product_id = SQ.product_id
WHERE
    SQ.match_count = (SELECT COUNT(*) FROM Product_Search_Template)
1 голос
/ 01 апреля 2009

Вы можете присоединить таблицу к себе:

SELECT
prop1.product_id
FROM
properties prop1
JOIN properties prop2
    ON prop1.product_id = prop2.product_id
WHERE
prop1.property = 'color' and prop1.value = 'red'
and prop2.property = 'size' and prop2.value = 'small'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...