【问题标题】:SQL table design with common and distinct data具有共同和不同数据的 SQL 表设计
【发布时间】:2020-07-10 22:55:34
【问题描述】:

我是 SQL 新手,想知道在某些数据常见而某些数据不同时如何设计表。这不是一个真实的例子,但它说明了这一点。我想存储有关各种项目的数据。所有物品都有一些共同的数据——ID, Name, Description, CountryOfOrigin, UseByDate等。但是,根据物品的类型,有一些特定的属性需要存储,这些属性对于这种类型是不同的。有点像对象继承,有共同的根类型,还有根类型的各种特化。

我可以为每个项目类型创建不同的表,但是每个表都有自己的Name, Description, CountryOfOrigin, UseByDate 等。所以如果我想按UseByDate 列出项目,我将不得不搜索多个表。这听起来不是一个好方法。

然后我在想,也许我可以有一个名为 Items 的带有公共数据的表,这会以某种方式引用存储项目类型及其特定数据的其他表。请参阅以下示例:

CREATE TABLE Items
(
    ItemID integer PRIMARY KEY,
    Name text, -- Brand specific name or similar
    Description text,
    CountryOfOrigin text,
    UseByDate date
);

CREATE TABLE MilkVariety
(
    Type milk_type, -- FullFat, Skimmed, etc
    VolumeLitres integer,
    FatContent integer,
    PricePerLitre money
);

CREATE TABLE BreadVariety
(
    Type bread_type, -- White, WholeGrain, Baguette, etc
    WeightKilos integer,
    SugarContent integer,
    PricePerKilo money
);

但我不确定Items 表如何引用MilkVarietyBreadVariety。我可以引入外键,但看起来我必须为每种项目类型设置多个这样的键。这听起来不太对,因为单个项目不能同时是牛奶和面包类型。

关于如何处理这些事情有什么建议吗?谢谢。

【问题讨论】:

  • 我看不出你的例子。品种是否总是具有类型、重量/体积、糖/脂肪/碳水化合物含量和单价属性?
  • 是的,加上仅特定于该类型/品种的各种其他属性。例如,MilkVariety 可能是 (FullFat, 1.0, 30, 0.5),而表 Items 可能有两个相同牛奶品种但来自不同供应商的项目,因此品牌名称、原产国和使用日期可能不同。

标签: sql database-design


【解决方案1】:

根据您的评论,我假设各种食物将具有一致的属性。

您的项目表看起来不错。我在底部添加了几列。

Item
----
Item ID
Name
Description
Origin Country
Use By Date
Item Variety
Variety ID

Item Variety 是描述品种的 Varchar,如“bread”、“milk”。 Variety ID 是 Variety 表的外键。

 Variety
 -------
 Variety ID
 Type
 Measure Type
 Measure Amount
 Content Type
 Content Amount
 Price per measure

由于所有品种都在一个表中,因此您可以轻松地加入 Item 和 Variety 表。但是,您需要解释从数据库中读取的内容,可能使用某种编程语言。

【讨论】:

  • 感谢您的回答,但您已将所有品种类型汇总到一个名为 Variety 的表中。对于这样一个简单的示例,这可以正常工作,但假设品种类型可能包含非常不同的属性列表。对于一种类型,一个表可以有 5 列,对于另一种类型,它可以有 25 列,其中包含完全不同的数据。将它们全部放在一个单一的品种表中会很混乱。这不适用于许多不同的品种类型。我有点想弄清楚如何将 Items 表链接到多个 Variety 表,或者这不实用/可能吗?
  • @SadClouds:您在评论中说所有品种都具有相同的属性。如果他们不这样做,那么您将不得不使用某种形式的实体属性值模型。 en.wikipedia.org/wiki/…
【解决方案2】:

按照我的理解,在您的示例中,xVariety 表的整个标题独特且不可简化的 (KEY)。让我们接受这一点,并同意我们很高兴桌子在1NF 并保留它。
让我们也同意xVariety 表的数量是可管理的,比如少于 30 个——不推荐更多。

选项 1

这是首选选项。

从新的Variety 开始,所有其他xVariety 表的超类型。 VAR_ID 可能是在(用于)此表中生成的(自动增量)整数; VAR_TYP 是鉴别器。
在任何xVariety 表中插入新行之前,在此表中创建一个新的{VAR_ID, VAR_TYP}

-- Variety VAR_ID of type VAR_TYP exists.
--
Variety {VAR_ID, VAR_TYP}
     PK {VAR_ID}
     SK {VAR_ID, VAR_TYP}

CHECK (VAR_TYP IN ('Bread', 'Milk'))

xVariety 子类型是独占的,因此将VAR_TYP 添加到每个子类型以便更好地控制,注意FK {VAR_ID, VAR_TYP}

MilkVariety {
        VAR_ID
      , VAR_TYP   DEFAULT 'Milk'

      , MilkType    -- FullFat, Skimmed, etc
      , VolumeLitres
      , FatContent
      , ...  -- Other columns specific to this variety
      }
   PK {VAR_ID}
   AK {MilkType, VolumeLitres, FatContent, ...}

           FK {VAR_ID, VAR_TYP} REFERENCES
      Variety {VAR_ID, VAR_TYP}

      CHECK (VAR_TYP = 'Milk')


BreadVariety {
        VAR_ID
      , VAR_TYP   DEFAULT 'Bread'

      , BreadType   -- White, WholeGrain, etc
      , WeightKilos
      , SugarContent
      , ...  -- Other columns specific to this variety
      }
   PK {VAR_ID}
   AK {BreadType, WeightKilos, SugarContent, ...}

           FK {VAR_ID, VAR_TYP} REFERENCES
      Variety {VAR_ID, VAR_TYP}

    CHECK (VAR_TYP = 'Bread')

Items 现在可以引用Variety

Items { ItemID
      , Name_
      , Description
      , CountryOfOrigin
      , UseByDate

      , VAR_ID
      }
   PK {ItemID}

   FK {VAR_ID} REFERENCES Variety {VAR_ID}

选项 2

此选项提供的控制较少,但可能更易于管理。

每个表都有自己独立的(自动递增)ID;再次添加VAR_TYP 以获得更好的控制。

MilkVariety {
         MILK_ID
       , VAR_TYP    DEFAULT 'Milk'

         MilkType      -- FullFat, Skimmed, etc
       , VolumeLitres
       , FatContent
       , ...  -- Other columns specific to this variety
       }
    PK {MILK_ID}
    AK {MilkType, VolumeLitres, FatContent, ...}

    CHECK (VAR_TYP = 'Milk')


BreadVariety {
         BREAD_ID
       , VAR_TYP    DEFAULT 'Bread'

         BreadType     -- White, WholeGrain, etc
       , WeightKilos
       , SugarContent
       , ...  -- Other columns specific to this variety
       }
    PK {BREAD_ID}
    AK {BreadType, WeightKilos, SugarContent, ...}

    CHECK (VAR_TYP = 'Bread')

现在是一个视图 {VAR_TYP, VAR_TYP_ID}

-- view (logically)
--
Variety {VAR_TYP, VAR_TYP_ID}
     PK {VAR_TYP, VAR_TYP_ID}

一个例子:

CREATE VIEW Variety AS
SELECT VAR_TYP
     , MILK_ID AS VAR_TYP_ID
FROM MilkVariety
UNION
SELECT VAR_TYP
     , BREAD_ID AS VAR_TYP_ID
FROM BreadVariety ;

注意视图必须UNION所有xVariety表。如果我们能够(以某种方式)实现这一观点,那就太好了,那么FK 就有可能实现它。但是,暂时不要讨论这个问题。

{VAR_TYP, VAR_TYP_ID} 添加到Items

Items { ItemID
      , Name_
      , Description
      , CountryOfOrigin
      , UseByDate

      , VAR_TYP
      , VAR_TYP_ID
      }
   PK {ItemID}

     -- how to implement this?
     FK {VAR_TYP, VAR_TYP_ID} REFERENCES
Variety {VAR_TYP, VAR_TYP_ID}

FK 必须以某种方式实现。如果视图是物化的,根据 RDBMS,可能可以在 SQL 中指定约束;否则,应用程序必须处理它。

如果xVariety 表很少更改,比如每周一次,那么视图Variety {VAR_TYP, VAR_TYP_ID} 实际上可能会变成一个表。然后,加载xVariety 表的同一进程可以使用查询填充表。在这种情况下,可以从Items 获得FK

加入时使用{VAR_TYP, VAR_TYP_ID},以确保不会加入错误的表。

SELECT *
FROM Items        AS a
JOIN BreadVariety AS b ON  b.VAR_TYP_ID = a.VAR_TYP_ID
                       AND b.VAR_TYP    = a.VAR_TYP
WHERE a.CountryOfOrigin = 'US';

注意事项

All attributes (columns) NOT NULL

PK = Primary Key
AK = Alternate Key   (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多