假设我有Product
,Category
和Product_To_Category
表格。产品可以分为多个类别。
Product Category Product_to_category ID | NAME ID | Name Prod_id | Cat_id ===================== ============ =================== 1| Rose 1| Flowers 1| 1 2| Chocolate Bar 2| Food 2| 2 3| Chocolate Flower 3| 1 3| 2
我想要一个SQL查询,它给我一个结果,如
ProductName | Category_1 | Category_2 | Category_3 ======================================================= Rose | Flowers | | Chocolate Flower | Flowers | Food |
等
我能够做到这一点的最好方法是将一堆查询结合在一起;对给定产品的每个预期数量的类别进行一次查询。
select p.name, cat1.name, cat2.name
from
product p,
(select * from category c, producttocategory pc where pc.category_id = c.id) cat1,
(select * from category c, producttocategory pc where pc.category_id = c.id) cat2
where p.id = cat1.id
and p.id = cat2.id
and cat1.id != cat2.id
union all
select p.name, cat1.name, null
from
product p,
(select * from category c, producttocategory pc where pc.category_id = c.id) cat1
where p.id = cat1.id
and not exists (select 1 from producttocategory pc where pc.product_id = p.id and pc.category_id != cat1.id)
这有几个问题。
有谁知道更好的方法吗?此外,这种技术有技术名称吗?
答案 0 :(得分:9)
我不知道您使用的是哪种RDBMS,但在MySQL中您可以使用GROUP_CONCAT:
SELECT
p.name,
GROUP_CONCAT(c.name SEPARATOR ', ') AS categories
FROM
product p
JOIN product_to_category pc ON p.id = pc.product_id
JOIN category c ON c.id = pc.category_id
GROUP BY
p.name
ORDER BY
p.name,
c.name
答案 1 :(得分:1)
您无法使用严格的SQL查询创建这些结果。您要生成的内容称为数据透视表。许多报告工具都支持这种行为,您可以在其中选择产品和类别,然后将类别转换为数据透视列。
我相信SQL Server Analysis Services也支持这样的功能,但我对SSAS没有任何经验。
答案 2 :(得分:1)
SELECT p.name, cat_food.name, cat_flowers.name
FROM
product p
left outer join Product_to_category pc_food
on p.id = pc_food.Prod_id
left outer join Category cat_food
on pc_food.Cat_id = cat_food.id
AND cat_food.name = 'Food'
left outer join Product_to_category pc_flowers
on p.id = pc_flowers.Prod_id
left outer join Category cat_flowers
on pc_flowers.Cat_id = cat_flowers.id
AND cat_flowers.Name = 'Flowers'
只有在知道了可能的类别数量时才能将它们放入列中。这就是(标准)SQL的工作原理,列数不是动态的。
答案 3 :(得分:1)
Seb的回答让我走上正确的道路寻找解决方法。我正在使用Oracle,它具有模拟MYSQL group_concat
的功能。这是一个例子。这不会生成列,因此不如纯SQL解决方案好,但它适合我目前的用途。
with data as
(
select
pc.id cat,
p.id prod,
row_number() over( partition by p.id order by pc.id) rn,
count(*) over (partition by p.id) cnt
from product_to_category pc, product p
where pc.product_id = p.id
)
select prod, ltrim(sys_connect_by_path(cat, ','), ',') cats
from data
where rn = cnt
start with rn = 1 connect by prior prod = prod and prior rn = rn - 1
order by prod
这会生成
等数据PROD | CATS =========== 284 | 12 285 | 12 286 | 9,12
我可以根据需要编辑ltrim(sys_connect_by_path())列,以生成我需要的任何数据。