【问题标题】:SQL Server Table Design with Table having foreign key to two other tablesSQL Server 表设计,其中表具有其他两个表的外键
【发布时间】:2014-08-27 04:33:38
【问题描述】:

我有四张桌子,
DiscountCode 描述折扣。 基本上作为产品出售的捆绑包,因此它包含产品代码 作为产品出售的产品,因此它还包含产品代码 ProductDiscount 代码旨在用于描述捆绑/产品可以有多个与之关联的折扣代码这一事实。

**Discount Code**
Id
Name
Code  ex. SUMMER10  ie 10% off summer products
...

**Bundles**
Id
Name
ProductCode  *Unique*  Ex..ABC123
...

**Products**
Id
Name
ProductCode  *Unique*  Ex.. XYZ1234
...

**ProductDiscountCode**
DiscountId
ProductCode   FK to both Products.ProductCode  AND Bundles.ProductCode

Records in ProductDiscountCode:
1   ABC123
1   XYZ1234
1   URS576  <-- prevent this if Prod or Bundle does NOT contain URS576

我的问题是关于三元表中的 ProductCode。现在请记住 PELASE SQL 不是我的强项!三元表中的 ProductCode 列是否可以/应该外键到两个单独的表,以试图将其内容限制为包含在 Bundle 表或 Product 表中的产品代码,假设 bundles 和 products 中的产品代码是唯一的在两个表之间(由业务规则强制执行)。还是ProductDiscountCode表需要以下的

**ProductDiscountCode**
DiscountId
ProductCode  FK to ProductCode in Product
BundleCode   FK to ProductCode in Bundle

【问题讨论】:

  • 如果你在做表设计,SQL需要成为你的强项。

标签: sql sql-server


【解决方案1】:

好的,尝试将同一字段限制为两个不同的 FK 绝不是一个好主意,这是设计不正确的标志。

如果不使用产品表中的产品代码,为什么要捆绑一个单独的表?为什么不在产品表中添加一列来确定该行项目是捆绑产品还是单个产品,然后将两者都停在那里?

【讨论】:

  • 因为捆绑包是作为产品销售的,并且除了包含的产品之外还有自己的产品代码...
  • 那么既然它们是作为产品出售的,最好把它们放在产品表中
  • 捆绑包的属性与单个产品项目不同...可以将其想象为包含控制器的 Xbox 捆绑包...作为单个项目出售的控制器具有自己的属性和代码本身,但是包含两个控制器的盒子包也有它自己的属性和它自己独特的产品代码,在我们的例子中,我们需要跟踪包中的哪些项目......这就是它们被分开的原因
  • 不,您将捆绑包放在产品表中,因为它是一个产品,并且您有一个捆绑产品表(1-many realtionship),其中捆绑产品 ID 作为捆绑 ID,各个元素 prod产品作为产品 ID。然后两次join到product表,查询时获取bundlename和单独的产品名。
  • 我在上一份工作中解决了这个确切的问题,所以我很熟悉你想要完成的事情。
【解决方案2】:

如果您要使用外键,那么每个值都必须作为键存在于另一个表中,因此如果您的列 Product Keys 中包含捆绑键,则您不能限制它,反之亦然。

如果您需要确保参照完整性,那么您需要有两个 Nullable 列。

您可能还应该有一个检查约束来确保一个且只有一个代码为空。

CREATE TABLE ProductDiscountCode
(
DiscountId int,
ProductCode  varchar(12) null,
BundleCode   varchar(12) null,

CONSTRAINT ProductDiscountCode_PK PRIMARY KEY(DiscountId),

CONSTRAINT FK_ProductDiscountCode_DiscountId FOREIGN KEY (DiscountId) REFERENCES DiscountCode (Id),
CONSTRAINT FK_ProductDiscountCode_BundleCode FOREIGN KEY (BundleCode) REFERENCES Bundle (ProductCode),
CONSTRAINT FK_ProductDiscountCode_ProductCode FOREIGN KEY (ProductCode) REFERENCES Product (ProductCode),

CONSTRAINT ProductCodeExists CHECK (
                                   (ProductCode IS NULL AND BundleCode IS NOT  NULL) 
                                   OR 
                                   (ProductCode IS NOT NULL AND BundleCode IS NULL)
                                   )
)

如果出于某种原因您确实需要能够将产品代码显示为单列,那么您可以按照这些方式做一些事情

CREATE TABLE ProductDiscountCode
(
DiscountId int,
SingleProductCode  varchar(12) null,
BundleCode   varchar(12) null,
ProductCode as ISNULL (SingleProductCode  ,BundleCode  ) ,
CONSTRAINT ProductDiscountCode_PK PRIMARY KEY(DiscountId),
CONSTRAINT FK_ProductDiscountCode_DiscountId FOREIGN KEY (DiscountId) REFERENCES DiscountCode (Id),
CONSTRAINT FK_ProductDiscountCode_BundleCode FOREIGN KEY (BundleCode) REFERENCES Bundle (ProductCode),
CONSTRAINT FK_ProductDiscountCode_SingleProductCode FOREIGN KEY (SingleProductCode) REFERENCES Product (ProductCode),
CONSTRAINT SingleProductCodeExists CHECK ((SingleProductCode IS NULL AND BundleCode IS NOT  NULL) OR (SingleProductCode IS NOT NULL AND BundleCode IS NULL))
)

但您必须首先问自己是否真的有必要首先使用外键限制。

为产品代码设置两列可能会稍微加快您的 Select 查询,但必须决定在更新、删除和插入中存储产品代码的列。

【讨论】:

  • 但是 ProductDiscountCode 表中 ProductCode 的每个值都会有一个 ProductCode 存在于 Products 或 Bundles 中,这不能满足您的第一个要求?
  • 例如 ABC123 要么存在于 Products 要么 Bundles 中,但永远不会同时存在
  • 每个外键约束本身就是一个约束。如果一个满意,那并不意味着你打破了另一个。
【解决方案3】:

请先看帖:Multiple foreign key constraints on a single column in SQL Server 2008

ProductCode 是 Bundle 中的 FK,然后您希望 ProductDiscountCode 中同一列的另一个外键。您重复引用同一字段,这似乎不是一个好的设计。您应该在插入时限制表中的值,约束并不适用于所有类型的验证。

【讨论】:

    猜你喜欢
    • 2013-07-27
    • 2020-03-30
    • 2015-02-13
    • 2019-05-19
    • 2019-02-18
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多