我正在开发一个系统来处理会员的定期结算。可以将要购买的物品组合在一起以获得特殊包装费率,或者单独购买以获得更高的独立费率。我的数据库模式中确定要为重复项目支付的金额的部分包含以下4个表:
MEMBER_RECUR_GROUP
member_id(PK)
recur_group_id(PK)
RECUR_GROUP
recur_group_id(PK)
RECUR_GROUP_ITEM
recur_group_id(PK)
recur_item_id(PK)
recur_amount
RECUR_ITEM
recur_item_id(PK)
ITEM_CODE
recur_term
基本上,项目附加到重复组,然后与成员关联。同一项目可以出现在给定成员的多个重复组中。
例如,假设我们有3个简单的项目:苹果,橙子和香蕉。可以有一个包含所有3个的重复组(该组中的单个项目价格将是最便宜的,比如说每个1美元)。只有2件物品可以有一个复活组,比如橙色和香蕉。只有苹果可以有一个复发组(它的单独价格,比如2美元,高于它在其他组中的“打包”价格),另一个只是橙色,另一个只是香蕉。
给定一个member_id和一个或多个item_codes(可能是CSV,类似“apple,banana”),我想查询从包含所有item_codes的recur_group返回每个item_code的recur_term和recur_amount。如果没有包含所有项目的recur_group,则应返回单个项目的独立recur_group中的recur_term和recur_amount值。这可以在单个查询中实现吗?
如果实现很重要,我正在使用SQL Server 2005。谢谢!
以下是样本数据,预期结果如下。
MEMBER_RECUR_GROUP
1,1,
1,3 1,4 1,5,
RECUR_GROUP
1
2
3
4
5
RECUR_GROUP_ITEM
1,1,1.00
1,2,1.00
1,3,1.00
2,2,1.50 2,3,1.50
3,1,2.00 4,2,2.00 5,3,2.00
RECUR_ITEM
1,苹果,3
2,橙色,3
3,香蕉,3
如果会员ID 1为apple,orange和banana自动计费,则使用recur group ID 1的定价。
如果成员ID 1为苹果和橙色自动计费,则使用复发组ID 3和4的组合定价。 (因为会员ID 1没有带苹果和橙色的复发组。)
如果会员ID 1为橙色和香蕉自动计费,则使用重复组ID 2的定价
如果成员ID 1为Apple自动计费,则使用复发组ID 3的定价
如果会员ID为橙色自动开票,则使用复牌组ID 4的定价
如果会员ID为香蕉自动计费,则使用复发组ID 5的定价。
答案 0 :(得分:0)
这可能会让你朝着正确的方向前进。首先,最大的问题是即使是中等数量的项目和/或群体,这种计算也会失控。
我在这里提出的查询是为MySQL编写的,我确信其中的一些内容在SQL Server中不可用,但你可以调整它,我敢肯定。我不得不跳过很多针对MySQL的箍,以获得每个项目组合最便宜的行。据我所知,MS SQL实际上更容易,因为它似乎支持FIRST聚合函数。
此外,您没有指定某人是否有理由获得同一项目的倍数。我假设没有,但如果你删除了having子句,它将包含倍数。
核心问题是您需要生成可能包含所有购买元素的组的所有可能组合。要做到这一点,recur_group表必须与自己连接,直到购买的项目数。在我的示例查询中,我最多包含4个自连接,这些连接将涵盖最多4个项目的所有可能组合。
如果组和价格不经常更改,您可以将查询结果存储到每当数据发生变化时重新填充的表中。
但最重要的是,你可能需要简化一些事情,除非你只有很少的团体和物品。
set @type = '';
set @num = 1;
select item_list, total, g1, g2, g3, g4,
@num := if(@type = item_list, @num + 1, 1) as row_number,
@type := item_list as dummy
from (
select group_concat(i.item_code order by i.item_code separator ',')
as item_list,
( select sum(recur_amount)
from recur_group_item
where recur_group_id in (
perms.g1, perms.g2, perms.g3, perms.g4
)) as total,
perms.g1, perms.g2, perms.g3, perms.g4
from recur_item i
join recur_group_item gi
on gi.recur_item_id = i.recur_item_id
join (
select recur_group_id as g1,
null as g2, null as g3, null as g4
from recur_group
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
null as g3, null as g4
from recur_group g1, recur_group g2
where g1.recur_group_id < g2.recur_group_id
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
g3.recur_group_id as g3, null as g4
from recur_group g1, recur_group g2, recur_group g3
where g1.recur_group_id < g2.recur_group_id
and g2.recur_group_id < g3.recur_group_id
union
select g1.recur_group_id as g1, g2.recur_group_id as g2,
g3.recur_group_id as g3, g4.recur_group_id as g4
from recur_group g1, recur_group g2, recur_group g3, recur_group g4
where g1.recur_group_id < g2.recur_group_id
and g2.recur_group_id < g3.recur_group_id
and g3.recur_group_id < g4.recur_group_id
) as perms
on gi.recur_group_id in (perms.g1, perms.g2, perms.g3, perms.g4)
group by perms.g1, perms.g2, perms.g3, perms.g4
having count(i.item_code) = count(distinct i.item_code)
order by item_list asc, total asc
) as groupings
group by item_list, total, g1, g2, g3, g4
having row_number = 1;
使用稍微扩展的数据集,会产生与此类似的结果:
item_list total g1 g2 g3 g4
----------------------------- ----- -- ------ ------ ------
apple 2.0 3 (null) (null) (null)
apple,banana 4.0 3 5 (null) (null)
apple,banana,onion 4.0 5 9 (null) (null)
apple,banana,onion,orange 5.0 2 9 (null) (null)
apple,banana,onion,pear 7.0 5 6 9 (null)
apple,banana,onion,pineapple 8.0 5 7 9 (null)
apple,banana,orange 3.0 1 (null) (null) (null)
apple,banana,orange,pear 6.0 1 6 (null) (null)
apple,banana,orange,pineapple 7.0 3 5 10 (null)
apple,banana,pear 7.0 3 5 6 (null)
apple,banana,pear,pineapple 11.0 3 5 6 7
apple,banana,pineapple 8.0 3 5 7 (null)
apple,onion 2.0 9 (null) (null) (null)
apple,onion,orange 4.0 4 9 (null) (null)
apple,onion,orange,pear 7.0 4 6 9 (null)
apple,onion,orange,pineapple 5.0 9 10 (null) (null)
apple,onion,pear 5.0 6 9 (null) (null)
apple,onion,pear,pineapple 9.0 6 7 9 (null)
apple,onion,pineapple 6.0 7 9 (null) (null)
apple,orange 4.0 3 4 (null) (null)
apple,orange,pear 7.0 3 4 6 (null)
apple,orange,pear,pineapple 8.0 3 6 10 (null)
apple,orange,pineapple 5.0 3 10 (null) (null)
apple,pear 5.0 3 6 (null) (null)
apple,pear,pineapple 9.0 3 6 7 (null)
apple,pineapple 6.0 3 7 (null) (null)
banana 2.0 5 (null) (null) (null)
banana,onion 8.0 5 8 (null) (null)
banana,onion,orange 9.0 2 8 (null) (null)
banana,onion,orange,pear 12.0 2 6 8 (null)
banana,onion,orange,pineapple 11.0 5 8 10 (null)
banana,onion,pear 11.0 5 6 8 (null)
banana,onion,pear,pineapple 15.0 5 6 7 8
banana,onion,pineapple 12.0 5 7 8 (null)
banana,orange 3.0 2 (null) (null) (null)
banana,orange,pear 6.0 2 6 (null) (null)
banana,orange,pear,pineapple 8.0 5 6 10 (null)
banana,orange,pineapple 5.0 5 10 (null) (null)
banana,pear 5.0 5 6 (null) (null)
banana,pear,pineapple 9.0 5 6 7 (null)
banana,pineapple 6.0 5 7 (null) (null)
onion 6.0 8 (null) (null) (null)
onion,orange 8.0 4 8 (null) (null)
onion,orange,pear 11.0 4 6 8 (null)
onion,orange,pear,pineapple 12.0 6 8 10 (null)
onion,orange,pineapple 9.0 8 10 (null) (null)
onion,pear 9.0 6 8 (null) (null)
onion,pear,pineapple 13.0 6 7 8 (null)
onion,pineapple 10.0 7 8 (null) (null)
orange 2.0 4 (null) (null) (null)
orange,pear 5.0 4 6 (null) (null)
orange,pear,pineapple 6.0 6 10 (null) (null)
orange,pineapple 3.0 10 (null) (null) (null)
pear 3.0 6 (null) (null) (null)
pear,pineapple 7.0 6 7 (null) (null)
pineapple 4.0 7 (null) (null) (null)