使用多对多关系使查询量保持不变

时间:2018-05-27 18:48:29

标签: mysql sql

我有一个有多对多关系的实体:
Product,可以有许多类别和许多标签。 TagCategory也可以有很多产品。

现在的架构是:

products
-------------
product_id
name

categories
-------------
category_id
name

tags
-------------
tag_id
name

products_categories
-------------
product_id
category_id

products_tags
-------------
product_id
tag_id


我需要在一个页面中显示包含所有标签和类别的产品列表 问题是我执行的查询数量是2n + 1,其中n是页面中列出的产品数量。

基本上我先做的是:

select product_id, name from products

然后在我的应用程序的循环中,我执行这些查询(伪代码):

tags = []
categories = []
for each product
    tags[product_id] = select t.tag_id, t.name 
                       from products_tags as pt 
                       join tags t 
                           on pt.tag_id = t.tag_id
                       where pt.product_id = {product_id}

    categories[product_id] = select c.category_id, c.name 
                             from products_categories as pc 
                             join categories c 
                                 on pc.category = c.category_id
                             where pc.product_id = {product_id}
end for each


是否有一种很好的方法可以使执行的查询数量与查询的记录数无关?

修改
对于每种产品,我需要以这种格式显示数据:

-------------------------------------------------------
| Product name: A good smartphone                     |
| Categories: Tech, Smartphone                        |
| Tags: smartphone, some-smartphone-brand, 4g         |
|                                                     |
-------------------------------------------------------   

2 个答案:

答案 0 :(得分:0)

你可以试试这个(它依次使用带有标签和类别的连接,并用列table_type来区分它们):

select *, 'CAT' as table_type
from products p left join products_categories pc left join categories c  
ON p.product_id = pc.product_id and pc.category_id = c.category_id
UNION ALL
select *, 'TAG' as table_type
from products p left join products_tags pt left join tags t  
ON p.product_id = pt.product_id and pt.tag_id = t.tag_id
order by p.product_id 

答案 1 :(得分:0)

您可以使用单个查询从数据库和应用程序级别获取所有信息,根据您的需要构建数据。下面的查询将多次返回每个产品,但标签/类别不同。

select p.product_id, p.name, t.tag_id, t.name tag_name, c.category_id, c.cat_name 
from product p
join products_tags as pt on pt.product_id = p.product_id
join tags t on pt.tag_id = t.tag_id
join products_categories as pc on pc.product_id = p.product_id
join categories c on pc.category = c.category_id
order by p.product_id

伪代码

products = []
tags = []
categories = []
var productObj= {};
var product_id =false;
for each product
    /**
    * If product_id != product.id from loop iteration it means this is different product from previous iteration, Push this product object in `products[]`
    */
    if(product.id != product_id){
        products[product.id] = product;
        product_id = product.id;
    }
    /** you can put additional check here before insert in array if value is not present  `products[product.id][tags]` */
    products[product.id][tags][] = tag_name;

    /** you can put additional check here before insert in array if value is not present  `products[product.id][categories]` */ 
    products[product.id][categories][]= cat_name;
end for each

产品的样本对象/数据结构

[ 
    1 => [
    name => A good smartphone,
    categories => [Tech, Smartphone],
    tags => [smartphone, some-smartphone-brand, 4g]
    ],  
    2 => [
    name: Another product,
    categories => [Cat1, Cat2],
    tags => [Tag1, Tag2, .....]
    ],
.....
]