如何在数据库中创建和/或关系?

时间:2008-10-22 14:47:01

标签: database database-design

我有优惠券表。优惠券仅适用于某些商品或适用于整个商品类别。

例如:比萨12“ AND (1L百事可乐 OR 炸薯条)5美元优惠券

我能想到的最好的方法是制作一个CouponMenuItems表,其中包含coupon_id和位字段,如IsOr和IsAnd。它不起作用,因为在这个例子中我有2组项目。第二个是2个项目之间的OR关系。

我是怎么做到这一点的,所以实现的逻辑尽可能简单?

任何帮助或提示赞赏!

谢谢,

Teebot

5 个答案:

答案 0 :(得分:5)

通常,您可以使用Disjunctive Normal Form来简化此类事情。

您将逻辑规范化为一系列分离 - “或条款”。每个析取都是“和条款”。

因此,您的规则将成为以下长期分离。

  • 披萨 AND 百事可乐

  • 披萨 AND 炸薯条

(你总是可以做到这一点,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表中,有一个字段指示优惠券可以同时应用多少项,其中一些特殊值表示“无限”。