【问题标题】:Storing multiple values which are repeated in a table field存储在表字段中重复的多个值
【发布时间】:2020-01-03 18:28:04
【问题描述】:

我本身有三个对象,客户、产品和订单。 客户和产品一样都有自己的价值观。 当我需要为订单设置表格时出现问题,因为虽然它只有一个客户,因此很容易完成单向关系,我想不出如何在订单中制作产品列表(这是可变大小)。

例如案例:

客户表有以下字段:ID,Name

产品表有以下字段:ID、名称、价格

现在为了创建订单表,我遇到了这个问题:

Order:

 Id = 001

 Client_ID = 002

(链接到客户表)

Products = array? eg. ["milk","tomatoes","Thin_Crust Ham & Cheese Pizza no_Gluten"](会使用他们的 ID 这只是为了形象化)

当我第一次搜索这个时,最常见的答案是创建另一个表。 从我所见,创建另一个表实际上是不可能的,因为在这些示例中,它们在新创建的表中是唯一的(例如,有人想创建一个字段来存储“person”表中的一个人的多个电话号码,所以他们可以创建一个 telf.numbers 表,因为它们是唯一的,并将它们链接回相关的“人”。)

我看到的另一个选项是使用一个大的 varchar 字段,值之间有逗号。 如果这是唯一的其他方法,那么如果我们达到每个字段的 char 限制,会不会有问题?

【问题讨论】:

  • 我创建了一个与此类似的库存系统。我找到的解决方案是我的“PartList”,它包含许多部件 ID,将它们放在 JSON 格式中。在您的示例中,它看起来像这样:[{"ProductID:" "213"}, {"ProductID:" "211"}, {"ProductID:" "113"}]。我不确定这是否正是您要问的,但这就是我在应用程序中完成类似操作的方式。
  • 您需要 3 个以上的表。最佳 - 4 张桌子(我认为是这样)。分开ClientsProductsOrders(指客户)、OrderLines(指OrdersProducts,一个订单多行)。任何“类数组”数据类型,包括序列化(JSON、XML 等)都不是安全的解决方案。
  • 请参阅stackoverflow.com/questions/3653462/…,了解使用逗号分隔列表设计的更多缺点。

标签: mysql sql


【解决方案1】:

这是数据库设计中非常常见的场景,您希望在订单和产品之间创建n:m (Many to Many) 关系。这可以通过链接表来实现。

  • 可以使用逗号分隔的字符串、JSON、XML 或其他序列化方法将此数据存储在单个字符串列中,但这会使数据查询变得复杂,并且您会丢失一些使用 RDBMS 为您提供的强大功能。
  • 其他 RDBMS 允许 VARCHAR(MAX) 缓解存储序列化数据时的字段长度问题,在 MySQL 中只需将字段长度设置为非常大的数字,或使用最大值,如 @987654325 @。 See this topic for more help 如果你沿着这条路走。

Order 的概念情况下,这通常通过添加子表 OrderItem 来解决。 (或OrderLine)如果您在收据报告中看到此数据,则这些项目中的每一项都是收据上的,因此您可能会看到这称为Line 或 Line Items 方法。您在模型中需要的最少字段是:

  • 身份证
  • Order_ID
  • Product_ID

您可能会为此类表格考虑的其他常见字段包括:

  • 数量:对于用户可能选择Extra Tomatoes的场景,或者您可以简单地允许多行具有相同的Product_ID,也许您想要两者?
  • Cost_TaxEx:订单项的总成本(不含税)
  • 成本:总成本_包括_税。

这在 SQL 中可以这样表示:

CREATE TABLE Client (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Name VARCHAR(100)
)

CREATE TABLE Product (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Name VARCHAR(100),
    Price DECIMAL(13,2) /* Just an assumption on length */
)  

CREATE TABLE Order (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Client_ID INT NOT NULL,
    /* ... Insert other fields here ... */
    FOREIGN KEY (Client_ID)
        REFERENCES Client (ID)
)  

CREATE TABLE OrderItem (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Order_ID INT NOT NULL,
    Product_ID INT NOT NULL,
    /* ... Insert other fields here ... */
    FOREIGN KEY (Order_ID)
        REFERENCES Order (ID)
        ON UPDATE RESTRICT ON DELETE CASCADE, /* the cascade on order:orderitem is up to you */
    FOREIGN KEY (Product_ID)
        REFERENCES Product (ID) /*DO NOT cascade this relationship! */
)

上述解决方案允许Order 中有任意数量的Product 条目,但也允许重复的Product,如果您只需要对每个Order 强制执行一个产品,您可以添加一个对OrderItem 表的唯一约束:

CREATE TABLE OrderItem (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Order_ID INT NOT NULL,
    Product_ID INT NOT NULL,
    /* ... Insert other fields here ... */
    UNIQUE(Order_ID,Product_ID),
    FOREIGN KEY (Order_ID)
        REFERENCES Order (ID)
        ON UPDATE RESTRICT ON DELETE CASCADE, /* the cascade on order:orderitem is up to you */
    FOREIGN KEY (Product_ID)
        REFERENCES Product (ID) /*DO NOT cascade this relationship! */
)

【讨论】:

  • 正确,但这是订单和产品之间的 m:n 关系;一个订单可以有多个产品,一个产品可以出现在多个订单中。
  • 有问题吗? (您是否想要 1:n 而不是 n:n)如果是这样,请向表中添加约束或在 UI 中对其进行管理。 OP 的措辞表明,强制唯一性可能会导致其设计出现问题
  • 此解决方案启用了另一个重要功能:记录下订单时为每个产品支付的价格。这允许产品价格上涨或下跌,但您可以准确记录收入。
  • 并允许在您的 UI 中使用逻辑,例如单个商品的“特价”、“折扣”或销售代表覆盖。也许一件物品损坏了,或者比平时小。如果Price 实际上是PricePerKg 那么OrderItem 有一个WeightKg 字段,而Cost 现在是WeightKg x PricePerKg 的计算...各种应用程序。
  • 对不起,我的评论只是想说,虽然你的解决方案是正确和好的,但解释是不正确的,因为这是一个 m:n 关系,而不是一个 1:n 关系你在第一段中说。例如,一个 1:n 关系是一个只能包含一个产品的订单。
猜你喜欢
  • 2011-09-23
  • 2014-09-09
  • 2012-03-30
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多