Как создать А / или отношения в базе данных? - PullRequest
4 голосов
/ 22 октября 2008

У меня есть таблица купонов. Купон может применяться только к определенным предметам или ко всей категории товаров.

Например: купон на 5 $ для пиццы 12 " И (1 л пепси ИЛИ картофель фри)

Лучшее, что я могу придумать, - это создать таблицу CouponMenuItems, содержащую coupon_id и битовые поля, такие как IsOr и IsAnd. Это не работает, потому что у меня есть 2 группы элементов в этом примере. Вторым является отношение ИЛИ между 2 элементами.

Любая идея о том, как я мог бы сделать это так, чтобы логика для реализации была настолько проста, насколько это возможно?

Любая помощь или кий приветствуется!

Спасибо

Teebot

Ответы [ 5 ]

5 голосов
/ 22 октября 2008

Часто вы можете упростить подобные вещи, используя Разъединительную нормальную форму .

Вы нормализуете свою логику в серии дизъюнкций - «или предложения». Каждый дизъюнкт представляет собой набор "и оговорок".

Итак, ваши правила становятся следующим долгим разделением.

  • Пицца И Пепси

OR

  • Пицца И картофель фри

(Кстати, вы всегда можете сделать это, используя любую логику. Проблема в том, что некоторые вещи могут быть действительно сложными. Хорошая новость заключается в том, что ни один специалист по маркетингу не будет пытаться придумать вам непонятно жесткую логику. Далее, переписать любой старая форма к дизъюнктивной нормальной форме - это легкий кусок алгебры.)

Это, как вы заметили, всегда имеет два уровня глубины: всегда список разделений верхнего уровня (любой из которых может быть истинным) и список конъюнктов более низкого уровня (все из которых должны быть истинными) .

Итак, у вас есть таблица «Условия» со столбцами, такими как идентификатор и название продукта. Это определяет простое сравнение между позицией и продуктом.

У вас есть таблица Conjuncts ("среднего уровня и предложения") со столбцами, такими как идентификатор соединения и идентификатор условия. Соединение между соединением и условием создаст все условия для соединения. Если все эти условия верны, конъюнкт верен.

Имеется таблица Disjuncts («верхнего уровня или предложения») со столбцами, такими как Ij и DJ. Если одно из этих дизъюнктов истинно, дизъюнкт истинно.

Соединение между дизъюнктами, конъюнктами и условиями создает полный набор условий, которые необходимо проверить.

2 голосов
/ 22 октября 2008

Один из возможных подходов к рассмотрению. Предполагая, что вы создали следующие классы:

+----------+        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 смогут позаботиться о сохранности такого домена классов.

1 голос
/ 22 октября 2008

Вам нужно будет сгруппировать все ваши отношения вместе, определить, как они группируются, а затем назначить купоны для этих отношений. По сути, вам нужны объекты базы данных для представления скобок в вашем примере, хотя вам понадобится еще одна внешняя скобка:

(Пицца 12 "И (1 л Пепси ИЛИ картофель фри))

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 пахнут мне, я думаю, что может быть желательна общая таблица Association, которая может обрабатывать любую из них, поэтому вы могли бы написать универсальный код для обработки всех отношений (хотя вы потеряете ссылочную целостность, если вы не обобщите Item и Group в единое целое).

Примечание: также при именовании группы объектов могут возникнуть проблемы. :)

0 голосов
/ 22 октября 2008

Мое предложение:

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 есть поле, указывающее, к скольким элементам купон может применяться одновременно, а какое-то специальное значение означает "бесконечный".

0 голосов
/ 22 октября 2008

Вы можете рассматривать отдельные элементы как свою собственную группу (1 участника) и просто применять чистую логику для отображения купонов на группы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...