避免可空的FK - 数据库设计

时间:2018-05-25 16:57:01

标签: sql database-design

我试图弄清楚如何在我的数据库中最好地表示我的数据,最好没有空FK(sql server)。

我有一个网站,用户必须购买会员资格(每月订阅),可以购买广告,购买积分以在网站上做更多的东西。

所以我在考虑使用这些表格

Company
 -normal company columns
Plan 
  - Limitations (json, that contains all the limitations of what membership allows, ie can do x amount of seraches)
   - Name (ie Membership lv 1)
   - Price
   - Qty 
   - Unit (Monthly, Credit, etc)
PlanTypes
    - Type (membership, addon, ad)
CompanyPlans (junction table)
    - PlanId
    - CompanyId
    - Limitations (Json) - this would store like when their membership expires or how many credits they have left. If they would extend membership or buy credits the rows would be updated, so there would be business rules to basically make sure 1 row per plan per company, though this would not work really for ads as they can buy more than 1 ad.
Ads
 - normal add columns
 - Start
 - End

所以我遇到的问题是,Plan table是跟踪他们的会员资格订阅,我认为是否正常的信用的表。

然而,当它到达广告时,它变得很奇怪,因为现在我正计划与Company建立关系。因此,现在广告突然检查它们是否仍处于活动状态是在广告表中完成的,其中所有其他内容都在CompanyPlan表中。

为了使情况更糟,广告的开始和结束日期是否仍会在CompanyPlan表中重复以保持一致性?

我真的不想尝试将Plan表拆分为Subscription Table,Addon table和Ad Table,因为我计划将order history & order history line table链接到所购买的产品,我不希望与Order历史记录行表有3种不同的关系,并且总是有2个FK关系为null,因为我认为这也很糟糕。

我想到的另一个选择但是我不确定这是不好的做法是将广告关系放在CompanyPlan Junction Table上并将开始/结束日期保留在Company Table和其他信息中Ad table.

示例数据

Company

Id Name
1  My Compnay

PlanTypes
Id  Type
1  Membership
2  Addon
3  Ad


Plans

Id PlanTypeId Limitations Name Price Value Unit
1   1         {Searches: 100} Plan 1 $30  1  Month
2   2         {}              Extra Searches $10  100 Credits
3   3         {}              Ad1    $100  1   Month

CompanyPlan
Id  PlanId   Limitations CompnyId
1   1        {Start: "2018-01-01", End: {2018-02-01}, 1
2   2        {ExtraSearches: 100}, 1
3   3        {AdStart: "2018-01-01", AdEnd: {2018-02-01}, 1

Ads
Id CompanyId Start End
1  1         2018-01-01  2018-02-01

Order History
Id  CompanyId
1    1

Order Lines
Id   OrderHistoryId  PlanId
1      1              1
2      1              2
3      1              3

2 个答案:

答案 0 :(得分:2)

对于像他在评论中已经提到过的Impaler这样的开始,如果正确使用,可以为空的FK并不是件坏事。我会设计你的表格如下:

Company
-Id
-Name

Plan
-Id
-Name
-Details

Addon
-Id
-Value

DefaultPlanAddon
-Id
-Plan_Id
-Addon_Id

Subscription
-Id
-Company_Id
-Plan_Id
-Start
-End

SubscriptionAddons
-Id
-Subscription_Id
-Addon_Id

Advertisement
-Id
-Subscription_Id
-Content
-Start
-End

我猜大多数表都非常简单。

<强>公司

识别公司/客户的所有数据。

<强>计划

有关计划的基本详情。

<强>附加组件

这里有点有趣。在此表中保存了所有插件。根据我的理解,插件可用于所有不同的计划。如果不是这种情况,您可以添加类似 PlanAddons 表的内容,其中包含计划可以包含哪些插件的信息。值包含此插件的内容。也许大约100个额外的添加或其他东西。至于我所知道你可以使用一个简单的字符串作为类型,因为插件基本上是一个Id和对这个插件的描述。

<强>订阅

我会分开订阅表。您还可以保存每个订阅的开始和结束日期。有了这个,你还有一个购买历史,不需要 OrderHistory 表。如果开始日期不等于购买日期,您可以轻松添加 PurchaseDate 列。

<强> SubscriptionAddon

此表包含特定订阅的所有插件,因为一个订阅可以包含许多插件。

<强> DefaultPlanAddon 此表存储每个计划的默认插件。此信息仅在公司购买订阅时使用。您的逻辑查找计划的默认插件,并将int与其他想要的插件一起放入 SubscriptionAddon 表中。

<强>广告

以下是存储的所有添加内容。还有开始和结束。与订阅一样,您也可以将此表用于 OrderHistrory

答案 1 :(得分:1)

在阅读完案例后,我认为这是:

  • 我认为广告表(广告)应存储广告的开始/结束日期。
  • companyads之间的关系为1:n。因此ads的外键指向company
  • 公司表格不应存储广告的开始/结束日期,因为同一公司将来可能会购买更多广告。如果是这样,新广告会在不影响旧广告的情况下获得开始/结束日期,此时此广告可能已过时。

这样可以保持模型清洁,没有(危险)冗余。