我正在尝试使用标记系统从数据库中选择产品。我已经读过,实现这一点的最好方法是通过多对多关系,因为当有大量记录时,使用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编码之前检查它是否有效,并且它可以工作。但这真的是最好的方法吗?我发现很难相信没有比为搜索的每个标签进行连接更好的方法。 谢谢你的建议。 :)
答案 0 :(得分: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调整为您要匹配的唯一标记的数量。请注意,如果这是用户输入的数据,他们会两次输入相同的标签。
答案 1 :(得分: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);