我有优惠券表。优惠券仅适用于某些商品或适用于整个商品类别。
例如:比萨12“ AND (1L百事可乐 OR 炸薯条)5美元优惠券
我能想到的最好的方法是制作一个CouponMenuItems表,其中包含coupon_id和位字段,如IsOr和IsAnd。它不起作用,因为在这个例子中我有2组项目。第二个是2个项目之间的OR关系。
我是怎么做到这一点的,所以实现的逻辑尽可能简单?
任何帮助或提示赞赏!
谢谢,
Teebot
答案 0 :(得分:5)
通常,您可以使用Disjunctive Normal Form来简化此类事情。
您将逻辑规范化为一系列分离 - “或条款”。每个析取都是“和条款”。
因此,您的规则将成为以下长期分离。
或强>
(你总是可以做到这一点,BTW,任何逻辑。问题是有些事情可能真的很复杂。好消息是没有营销人员会在你身上尝试令人困惑的逻辑。此外,任何改写 - 旧形式到析取范式是一个简单的代数。)
你会注意到,这总是两层深的:总是一个顶层的析取列表(其中任何一个都可能是真的)和一个较低级别的合取列表(所有这些都必须为真)
因此,您有一个“条件”表,其中包含id和产品名称等列。这定义了订单项和产品之间的简单比较。
您有一个Conjuncts(“mid-level and clause”)表,其中包含联合ID和条件ID等列。合取与条件之间的联合将产生合取的所有条件。如果所有这些条件都成立,则结合是真的。
有一个Disjuncts(“顶级或子句”)表,其中包含像disjunct Id和conjunct ID这样的列。如果这些分离中的一个是真的,那么分离是正确的。
析取,合取和条件之间的连接产生了你需要测试的一整套条件。
答案 1 :(得分:2)
一种可能的考虑方法。假设您创建了以下类:
+----------+ 1 +---------------+ *
| Coupon |<#>------>| <<interface>> |<--------------+
+----------+ | CouponItem | |
| +value | +---------------+ |
+----------+ | +cost() | |
+---------------+ |
/|\ |
| |
+--------------------------------+ |
| | | |
LeafCouponItem AndCouponItem OrCouponItem |
<#> <#> |
| | |
+-------------+---------+
和
class Coupon {
Money value;
CouponItem item;
}
interface CouponItem {
Money cost();
}
class AndCouponItem implements CouponItem {
List<CouponItem> items;
Money cost() {
Money cost = new Money(0);
for (CouponItem item : items) {
cost = cost.add(item.cost());
}
return cost;
}
}
class OrCouponItem implements CouponItem {
List<CouponItem> items;
Money cost() {
Money max = new Money(0);
for (CouponItem item : items) {
max = Money.max(max, item.cost);
}
return max;
}
}
class LeafCouponItem implements CouponItem {
Money cost;
Money cost() {
return cost;
}
}
并映射到2个表:
COUPON COUPON_ITEM
------ -----------
ID ID
VALUE COUPON_ID (FK to COUPON.ID)
DISCRIMINATOR (AND, OR, or LEAF)
COUPON_ITEM_ID (FK to COUPON_ITEM.ID)
DESCRIPTION
COST
因此,对于您的示例,您将拥有:
> SELECT * FROM COUPON
ID 100
VALUE 5
和
> SELECT * FROM COUPON_ITEM
ID COUPON_ID DISCRIMINATOR COUPON_ITEM_ID DESCRIPTION COST
200 100 AND NULL NULL NULL
201 100 LEAF 200 PIZZA 10
202 100 OR 200 NULL NULL
203 100 LEAF 202 PEPSI 2
204 100 LEAF 202 FRIES 3
这种单表方法是高度非规范化的,有些人希望为每个CouponItem实现都有单独的表。
大多数ORM框架都能够处理这类域的持久性。
答案 2 :(得分:1)
您需要将所有关系组合在一起,定义它们的分组方式,然后将优惠券分配给这些关系。基本上,您需要数据库实体来表示示例中的括号,但您还需要一个外括号:
(比萨12“和(1L百事可乐或炸薯条))
Coupon
CouponId
Name
...
Item
ItemId
Name
...
Group
GroupId
GroupMembership
GroupMembershipId
GroupId
ItemId
ItemAssociation
ItemAssociationId
Item1Id
Item2Id
IsOr : bit -- (default 0 means and)
GroupAssociation
GroupAssociationId
Group1Id
Group2Id
IsOr : bit -- (default 0 means and)
在对该结构进行头脑风暴之后,它看起来像是可以通过节点父/子关系层次结构解决的问题。 ItemAssociation / GroupAssociation表对我来说很有趣,我认为可以处理一个可以处理任何一个的通用关联表,所以你可以编写通用代码来处理所有关系(尽管你会失去参照完整性,除非你还将Item和Group概括为一个单一实体)。
注意:同样命名实体组可能会产生问题。 :)
答案 3 :(得分:0)
您可以将单个项目视为自己的组(1个成员),并实施纯逻辑以将优惠券映射到组。
答案 4 :(得分:0)
我的建议:
Table
primary key
= = = = =
COUPONS
coupon_id
PRODUCT_GROUPS
group_id
ITEM_LIST
item_id
ITEM_GROUP_ASSOC
item_id, group_id
COUPON_GROUP_ASSOC
coupon_id, group_id
COUPON_ITEM_ASSOC
coupon_id, item_id
在COUPON_ITEM_ASSOC
表中,有一个字段指示优惠券可以同时应用多少项,其中一些特殊值表示“无限”。