2012-01-11 1 views
2

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

У меня есть 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 для него, и он работает. Но действительно ли это лучший способ сделать это? Мне трудно поверить, что нет лучшего способа сделать это, чем сделать соединение для каждого найденного тега. Спасибо за любой совет. :)

ответ

3

Не нужно делать несколько соединений. Если вам нужно, чтобы соответствовать все тегам, вы можете использовать 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 как число уникальных тегов вы совпадающие по. Остерегайтесь, если это введенные пользователем данные, и они вводят один и тот же тег дважды.

+0

Спасибо, что работали великолепно. :) – Fourjays

1
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); 
Смежные вопросы