Recipe/Ingredient/Measurement/Amount 的数据库架构

Database Schema for Recipe/Ingredient/Measurement/Amount

我正在开发一个食谱应用程序来帮助我妻子培养她的蛋糕爱好。这个想法是创建一个食谱数据库来保存她所有的蛋糕食谱。

每个食谱都有多种成分。每种成分都会有测量值(克、毫升、茶匙等),然后是数量。

我了解如何创建 'recipes' 和 'ingredients' table 以及如何 link 2 与 table 'recipe_ingredients,但是我正在为如何实现测量和金额字段而苦苦挣扎。

任何具有更多数据库经验的人都可以建议数据库方案或有任何处理此问题的技巧吗?

像这样的东西应该可以工作:

CREATE TABLE `recipe` (
   `recipe_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `name` varchar(128) DEFAULT NULL,
   `description` text,
   `instructions` text,
   PRIMARY KEY (`recipe_id`)
)

CREATE TABLE `ingredient` (
   `ingredient_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `ingredient` varchar(64) DEFAULT NULL,
   PRIMARY KEY (`ingredient_id`)
)

CREATE TABLE `xref_recipe_ingredient` (
   `recipe_id` int(10) unsigned NOT NULL,
   `ingredient_id` int(10) unsigned NOT NULL,
   `amount` decimal(4,2) DEFAULT NULL,
   `unit` varchar(8) DEFAULT NULL,
   INDEX (`recipe_id`)
)

这包含一个食谱 table(每个食谱一个条目)以保存食谱的名称、描述和一组说明;一种成分 table 来保存可能的成分列表,包括成分的名称;以及 table 到 link 食谱和配料的交叉引用,包括食谱配料的数量和单位。

对此您有一些选择,并且像大多数事情一样,您可以走简单的路线(尼克·库恩斯在我输入这篇文章时发布了一个很好的例子)或逐渐复杂的路线。这里有一些关于你如何看待这个工作的问题要问你自己:

  1. 您想要测量结果的一致性吗? (你想始终为茶匙显示 "tsp",还是可以像 Nick 的示例那样自由显示)
  2. 您需要多久添加一次单位?随着时间的推移,您是否需要添加 dram 或 hogshead,或任何单位,或者您可能只是坚持基本原则?

一个好的中间立场应该是

CREATE TABLE `recipe` (
  `recipe_id`    INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name`         VARCHAR(128) DEFAULT NULL,
  `description`  TEXT,
  `instructions` TEXT,
  PRIMARY KEY (`recipe_id`)
)

CREATE TABLE `ingredient` (
  `ingredient_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `recipe_id`     INT(10) UNSIGNED NOT NULL,
  `ingredient`    VARCHAR(64) DEFAULT NULL,
  `amount`        DECIMAL(4, 2) DEFAULT NULL,
  `unit`          ENUM ('tsp', 'tbsp', 'oz', 'g', 'lb', 'cup', 'gallon', 'pinch') DEFAULT NULL,
  PRIMARY KEY (`ingredient_id`)
)

这通过强制执行一组单位来满足 #1,这很好。缺点是您必须更改 table 才能更新单位。使您的前端与有效选择保持同步也可能更加困难。

接下来,您可以为单位添加 table 并通过外键从成分 table 中引用它,如下所示:

CREATE TABLE `unit` (
  `unit_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `label`   VARCHAR(64) DEFAULT NULL,
  `sort`    INT(10) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`unit_id`),
  UNIQUE KEY `unit_label_uk` (`label`)
)

CREATE TABLE `ingredient` (
  `ingredient_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `unit_id`       INT(10) UNSIGNED NOT NULL,
  `recipe_id`     INT(10) UNSIGNED NOT NULL,
  `ingredient`    VARCHAR(64) DEFAULT NULL,
  `amount`        DECIMAL(4, 2) DEFAULT NULL,
  `sort`          INT(10) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`ingredient_id`)
)

这满足了#1 和#2,允许您轻松管理您的单位并访问列表以在您的前端使用,因此您在更改单位时不必更改您的前端。

从那里你可以分拆到 space 想出处理单位转换等的方法,但这对于你正在尝试做的事情来说可能有点矫枉过正。

编辑: 根据您的评论,我会这样设置:

CREATE TABLE `recipe` (
  `recipe_id`    INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name`         VARCHAR(128) NOT NULL,
  `description`  TEXT,
  `instructions` TEXT,
  PRIMARY KEY (`recipe_id`)
)

CREATE TABLE `ingredient` (
  `ingredient_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `label`         VARCHAR(64) NOT NULL,
  `sort`          INT(10) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`ingredient_id`)
  UNIQUE KEY `ingredient_label_uk` (`label`)
)

CREATE TABLE `unit` (
  `unit_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `label`   VARCHAR(64) DEFAULT NULL,
  `sort`    INT(10) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`unit_id`),
  UNIQUE KEY `unit_label_uk` (`label`)
)

CREATE TABLE `recipe_ingredient` (
  `recipe_ingredient_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `recipe_id`            INT(10) UNSIGNED NOT NULL,
  `ingredient_id`        INT(10) UNSIGNED NOT NULL,
  `unit_id`              INT(10) UNSIGNED NOT NULL,
  `amount`               DECIMAL(4, 2) DEFAULT NULL,
  `sort`                 INT(10) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`recipe_ingredient_id`)
)

您的 recipe_ingredient table 正在做这里的大部分工作,将所有内容捆绑在一起。