mysql - 订单和子订单的数据库设计

标签 mysql database oracle database-design relational-database

之前,我根据以下信息制作了这个数据库模式:一个订单有很多商品,每个商品可以属于很多订单。一个项目有一个标价,它会随着时间的推移而改变。应记录客户在特定日期购买商品的价格,用于历史报告。

CREATE TABLE item (
    item_id INT AUTO_INCREMENT
    ,item_name VARCHAR(30)
    ,item_list_price DECIMAL(10,2)
    ...
    CONSTRAINT ... PRIMARY KEY (item_id)
);
CREATE TABLE `order` (
    order_id INT AUTO_INCREMENT
    ,order_status VARCHAR(30)
    ,customer_id INT NOT NULL
    ...
    ,CONSTRAINT ... PRIMARY KEY (order_id)
);
CREATE TABLE order_item (
    order_item_id INT AUTO_INCREMENT
    ,order_id INT NOT NULL
    ,item_id INT NOT NULL
    ,order_item_quantity INT
    ,order_item_cost DECIMAL(10,2)
    ,CONSTRAINT ... PRIMARY KEY (order_item_id)
    ,CONSTRAINT ... FOREIGN KEY (order_id) REFERENCES `order` (order_id)
    ,CONSTRAINT ... FOREIGN KEY (item_id) REFERENCES `item` (item_id)
);

然而,我注意到一个项目可以有多个子项目。例如,一个汉堡包项可以有一个奶酪子项、一个培根子项等。据推测,每个子项应该能够属于许多项。奶酪可以放在汉堡包、意大利面等上。显然,不会有递归子项。

实现它的最佳方法是什么?

这是一种不使用继承的方法。创建一个子项表和一个 item_subitem 桥接表。 item_subitem 表包含到 Item 的强制 FK,但到 Subitem 的可为 null 的 FK。在 Order 表中,链接到 item_subitem。这不是正确的数据库继承,但在一定程度上模仿了它。

CREATE TABLE item (
    item_id INT AUTO_INCREMENT
    ,item_name VARCHAR(30)
    ,item_list_price DECIMAL(10,2)
    ...
    ,CONSTRAINT ... PRIMARY KEY (item_id)
);
CREATE TABLE subitem (
    subitem_id INT AUTOINCREMENT
    ,subitem_name VARCHAR(30)
    ,subitem_list_price DECIMAL(10,2)
    ...
    ,CONSTRAINT ... PRIMARY KEY (subitem_id)
);
-- Note how subitem_id is nullable
CREATE TABLE item_subitem (
    item_subitem_id INT AUTO_INCREMENT
    ,item_id INT NOT NULL
    ,subitem_id INT
    ,CONSTRAINT ... PRIMARY KEY (item_id, subitem_id)
    ,CONSTRAINT ... UNIQUE (item_subitem_id)
    ,CONSTRAINT ... FOREIGN KEY (item_id) REFERENCS item (item_id)
    ,CONSTRAINT ... FOREIGN KEY (subitem_id) REFERENCES subitem (subitem_id)
);

-- Note how this bridge table between order and item_subitem links to item_subitem's unique key
CREATE TABLE order_item_subitem (
    order_item_subitem_id INT AUTO_INCREMENT
    ,order_id INT
    ,item_subitem_id INT
    ,order_item_quantity INT
    ,order_item_cost DECIMAL(10,2)
    ,CONSTRAINT ... PRIMARY KEY (order_item_subitem_id)
    ,CONSTRAINT ... FOREIGN KEY (order_id) REFERENCES `order` (order_id)
    ,CONSTRAINT ... FOREIGN KEY (item_subitem_id) REFERENCES item_subitem (item_subitem_id)
);

这是处理这种情况的最佳方式吗?什么会更好?

最终用户应该能够查看他的历史购买记录(请记住标价在未来可能会发生变化)。这是一个订单的示例:

Order # 123456
Customer Name - Matthew Moisen
- Salad        $3
- Custom
   - Hamburger $5
   - Cheese    $1
   - Bacon     $1
- Apple        $1
-----------------
Total         $11

最佳答案

您所描述的称为“ bundle ”、“组合”或“营销包”。

您可以销售一种产品或一组产品。你应该在这里使用抽象/继承。

--using class table inheritance. postgresql syntax (sorry, but it's less verbose).

-- a product is an abstract thing you can sell, ex good, combo, service, warranty.
create table products (
  product_id int primary key
);

create table goods (
  product_id int primary key references products(product_id),
  name text not null unique
  ...other good columns
); 

create table bundles (
  product_id int primary key references products(product_id),
  name text not null unique
  ...other bundle columns
);

--map products to bundles:
create table bundle_products (
  bundle_id int references bundles(product_id),
  product_id int references products(product_id),

  primary key (bundle_id, product_id)
);

您需要使用关系除法(无余数)来防止重复捆绑。使用触发器。

--order line item points at products now:
create table line_items (
  order_id int references orders(order_id),
  display_order smallint not null default 0,
  product_id int not null references products(product_id),
  quantity int not null default 1,
  unit_price decimal(19,2) not null,

  primary key (order_id, display_order)
);

关于mysql - 订单和子订单的数据库设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22312900/

相关文章:

java - 如何使用java准备语句更新mysql时间戳列?

php - 是否可以让 wordpress 用户知道他们已经阅读了哪些帖子?

c# - ASP.NET 和 C# 用数据库中的数据填充表格

php - 榆树和数据库事务

sql - 返回每组一列最大值的行

mysql - 编程新手 : Why can I not alias an inline view in Oracle SQL?

mysql - 将我的 sql 查询转换为 laravel 查询

php - 移动应用程序网络服务的 Base64 编码消息问题

sql - 如何有效地找出哪条记录已被删除?

sql - 在分层数据中计算有约束的行数