4 votes

Comment créer des relations Et / Ou dans une base de données ?

J'ai une table de coupons. Un coupon peut être applicable à certains articles seulement ou à une catégorie entière d'articles.

Par exemple : un coupon de 5$ pour une Pizza 12". ET (1L Pepsi OU frites)

La meilleure solution que j'ai trouvée est de créer une table CouponMenuItems contenant un coupon_id et des champs binaires tels que IsOr et IsAnd. Cela ne fonctionne pas car j'ai deux groupes d'éléments dans cet exemple. Le second étant une relation OR entre deux éléments.

Avez-vous une idée de la manière dont je pourrais m'y prendre pour que la logique à mettre en œuvre soit aussi simple que possible ?

Toute aide ou indication est appréciée !

Gracias,

Teebot

5voto

S.Lott Points 207588

Souvent, vous pouvez simplifier ce genre de choses en utilisant les éléments suivants Forme normale disjonctive .

Vous normalisez votre logique en une série de disjonctions -- "clauses or". Chaque disjonction est un ensemble de "clauses et".

Vos règles deviennent donc la disjonction longue suivante.

  • Pizza ET Pepsi

OU

  • Pizza ET frites

(Vous pouvez toujours faire cela, BTW, avec n'importe quelle logique. Le problème est que certaines choses peuvent être vraiment compliquées. La bonne nouvelle, c'est qu'aucun responsable du marketing n'essaiera de vous imposer une logique difficile et déconcertante. De plus, la réécriture de la forme n'importe quel-ancien à la forme normale disjonctive est un morceau d'algèbre facile).

Vous remarquerez qu'il y a toujours deux niveaux de profondeur : toujours une liste de niveau supérieur de disjonctions (dont chacune peut être vraie) et une liste de niveau inférieur de conjonctions (qui doivent toutes être vraies).

Ainsi, vous avez une table "Conditions" avec des colonnes comme l'id et le nom du produit. Cela définit une comparaison simple entre le poste et le produit.

Vous disposez d'une table Conjonctions ("mid-level and clause") avec des colonnes telles que l'ID de la conjonction et l'ID de la condition. Une jointure entre conjonct et condition produira toutes les conditions pour la conjonct. Si toutes ces conditions sont vraies, la conjonction est vraie.

La table Disjuncts ("top-level or clause") contient des colonnes telles que disjunct Id et conjunct ID. Si l'une de ces disjonctions est vraie, la disjonction est vraie.

Une jointure entre les disjoncteurs, les conjoncteurs et les conditions produit l'ensemble complet des conditions que vous devez tester.

2voto

toolkit Points 27248

Une approche possible à envisager. Supposons que vous ayez créé les classes suivantes :

+----------+        1 +---------------+ *
| Coupon   |<#>------>| <<interface>> |<--------------+
+----------+          |   CouponItem  |               |
| +value   |          +---------------+               |
+----------+          | +cost()       |               |
                      +---------------+               |
                             /|\                      |
                              |                       |
           +--------------------------------+         |
           |                  |             |         |
      LeafCouponItem   AndCouponItem  OrCouponItem    |
                             <#>           <#>        |
                              |             |         |
                              +-------------+---------+

Et :

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;
    }
}

Et carte à 2 tables :

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            

Donc, pour votre exemple, vous auriez :

> SELECT * FROM COUPON

ID              100
VALUE           5

Et

> 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

Cette approche à table unique est fortement dénormalisée, et certains préféreraient avoir des tables séparées pour chaque implémentation de CouponItem.

La plupart des frameworks ORM seront capables de prendre en charge la persistance d'un tel domaine de classes.

1voto

cfeduke Points 13153

Vous devrez regrouper toutes vos relations, définir comment elles sont regroupées, puis attribuer des coupons à ces relations. Pour l'essentiel, vous avez besoin d'entités de base de données pour représenter la parenthèse dans votre exemple, mais vous aurez besoin d'une parenthèse extérieure supplémentaire :

(Pizza 12" ET (1L Pepsi OU frites))

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)

Après avoir réfléchi à cette structure, il semble qu'elle puisse être résolue par une hiérarchie de relations parent/enfant nodales. Les tables ItemAssociation/GroupAssociation me semblent bizarres, je pense qu'une table d'association générale qui pourrait gérer l'une ou l'autre pourrait être souhaitable afin que vous puissiez écrire un code général pour gérer toutes les relations (bien que vous perdiez l'intégrité référentielle à moins que vous ne généralisiez également Item et Group en une seule entité).

Remarque : le fait de nommer une entité Groupe peut également créer des problèmes :)

0voto

Ian Jacobs Points 4165

Vous pourriez traiter les articles individuels comme leur propre groupe (1 membre) et mettre en œuvre une logique pure pour faire correspondre les coupons aux groupes.

0voto

JosephStyons Points 21187

Ma suggestion :

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

Dans le COUPON_ITEM_ASSOC a un champ indiquant le nombre d'articles auxquels le coupon peut s'appliquer en même temps, avec une valeur spéciale indiquant "infini".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X