Выберите строки с несколькими тегами ... есть ли лучший способ? - PullRequest
2 голосов
/ 11 января 2012

Я пытаюсь создать систему тегов для выбора товаров из базы данных. Я читал, что лучший способ добиться этого - через отношение многие ко многим, так как использование LIKE '% tag%' замедлится при большом количестве записей. Я также прочитал этот вопрос, где для совпадения по нескольким тегам необходимо выполнить объединение для каждого запрашиваемого тега.

У меня есть 3 таблицы: shop_products, shop_categories и shop_products_categories. И мне нужно, например, быть в состоянии найти товары, которые имеют теги «цветы» и «романтика».

SELECT p.sku, p.name, p.path FROM shop_products p
  LEFT JOIN shop_products_categories pc1 ON p.sku = pc1.product_sku
  LEFT JOIN shop_categories c1           ON pc1.category_id = c1.id
  LEFT JOIN shop_products_categories pc2 ON p.sku = pc2.product_sku
  LEFT JOIN shop_categories c2           ON pc2.category_id = c2.id
WHERE c1.path = 'flowers' AND c2.path = 'romance'

Это демонстрационный запрос, который я сейчас создаю, чтобы проверить, работает ли он, прежде чем кодировать соответствующий PHP для него, и он работает. Но действительно ли это лучший способ сделать это? Мне трудно поверить, что нет лучшего способа сделать это, чем сделать объединение для каждого искомого тега. Спасибо за любой совет. :)

Ответы [ 2 ]

3 голосов
/ 11 января 2012

Нет необходимости делать несколько соединений.Если вам нужно сопоставить все теги, вы можете использовать предложение IN с таким подзапросом, как этот:

select p.sku, p.name, p.path 
from shop_products p
where p.sku in (
    select pc.product_sku 
    from shop_products_categories pc 
    inner join shop_categories c on pc.category_id = c.id
    where c.path in ('flowers', 'romance')
    group by pc.product_sku
    having count(distinct c.path) = 2
)

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

1 голос
/ 11 января 2012
SELECT
    p.sku, p.name, p.path  
FROM
    shop_products p 
    INNER JOIN
    (
        SELECT A.sku FROM
        (
            SELECT product_sku sku FROM shop_products_categories
            WHERE category_id=(SELECT id FROM shop_categories WHERE path='flowers')
        ) A
        INNER JOIN
        (
            SELECT product_sku sku FROM shop_products_categories
            WHERE category_id=(SELECT id FROM shop_categories WHERE path='romance')
        ) B
        USING (sku)
    ) flowers_and romance
    USING (sku)
;

Убедитесь, что у вас есть следующие индексы:

ALTER TABLE shop_categories ADD INDEX (path,id);
ALTER TABLE shop_categories ADD UNIQUE INDEX (path);
ALTER TABLE shop_products_categories ADD INDEX (product_sku,category_id);
...