我们需要构建一个树形视图,其中包含组结构和适合其下每个级别的所有产品的计数,如:
1 - Drink related (120)
> 11 - Plastic Cups (70)
> 111 - Vending Machine Cups (20)
> 1111 - Vending Machine Cups 100-150cc (12)
o Cup 1
o Cup 2
etc..
> 112 - Party Cups (25)
> 113 - Childrens Cups (25)
> 12 - Paper Cups (50)
2 - Food related (198)
> 21 - Plastic Plates (75)
etc...
所以,我们有两张桌子。一个拥有产品,一个拥有产品的组结构。每个产品行仅包含指向其所属组行的ID的直接外键链接,因此例如产品ID 42231具有对组ID 4的引用,因为它是具有特定大小的透明塑料杯。产品可以适用于任何组级别,如果它不适合特定类别,则不一定总是在第4组级别。 (例如,一个新的饮料杯系列可能被倾倒在Group ID 1“Drink Related”中,直到几个月后它最终获得自己的类别。)
组表(当前)有1800行,基本上形成一个类别树。每个组ID都是字母数字,因为有些组的变体太多而无法使用数字,所以:
ID Gp1 Gp2 Gp3 Gp4 Desc
1 1 0 0 0 Drink Related
2 1 11 0 0 Plastic Cups
3 1 11 111 0 Vending machine cups
4 1 11 111 1111 Vending machine cups 100-150cc
如果我只想显示每个ID中的确切产品数量,我可以这样做:
select *,
(select count(1)
from products
where groupID=g.id and isDeleted=0)
as groupProductCount
from groups g
order by g.group1, g.group2, g.group3, g.group4
...但我正在进行更加递归的计数,其中显示所有低于当前水平的产品的数量,所以我一眼就可以看到第1组中有120种与饮料相关的产品,而不是3种直接目前在组ID 1中。
就我个人而言,我认为我必须让DBA将4组级别添加到产品记录中,否则对于组表中的每条记录,我必须确定我们处于哪个级别(未使用级别的零,因此组4中的零表示我们处于级别3,组3中的零表示我们处于级别2等,然后扫描每个产品记录(当前为10,000并且正在增长)以查看是否它所属的组(通过外键组ID读取)的级别与我试图计算的当前组级别记录相匹配。
我看不出只有产品记录中的组ID才能有效实现这一目标。我在这里还是我错过了一些明显的东西?
答案 0 :(得分:0)
这是一个强力解决方案。 (我假设是SqlServer,但移植到其他人并不困难。)
WITH LeafGroup AS (
SELECT Id
,CASE WHEN Gp4 <> '0'
THEN Gp4
ELSE CASE WHEN Gp3 <> '0'
THEN Gp3
ELSE CASE WHEN Gp2 <> '0'
THEN Gp2
ELSE Gp1
END
END
END AS GroupId
FROM Groups
)
-- Build a delimited string from the groups
,DelimitedGroups AS (
SELECT Id
,Gp1 + '|' +
CASE WHEN Gp2 = '0' THEN '' ELSE Gp2 + '|' END +
CASE WHEN Gp3 = '0' THEN '' ELSE Gp3 + '|' END +
CASE WHEN Gp4 = '0' THEN '' ELSE Gp4 + '|' END AS Delim
FROM Groups
)
-- Find ids where the delimited string starts with the same groups
,ConnectedGroups AS (
SELECT DG1.Id AS TopId
, DG2.Id AS ConnectedId
FROM DelimitedGroups DG1
INNER JOIN DelimitedGroups DG2
ON LEFT(DG2.Delim, LEN(DG1.Delim)) = DG1.Delim
)
-- Now we can fetch all groups for each Id
,GroupsPerId AS (
SELECT ConnectedGroups.TopId AS Id
,LeafGroup.GroupId
FROM ConnectedGroups
INNER JOIN LeafGroup
ON ConnectedGroups.ConnectedId = LeafGroup.Id
)
-- Count all products for each id
SELECT GroupsPerId.Id
,COUNT(1)
FROM GroupsPerId
LEFT JOIN Products
ON GroupsPerId.GroupId = Products.GroupId
GROUP BY GroupsPerId.Id