17

私は、バック オブ ハウスの在庫システムと直接通信するため、非常に柔軟である必要があるレシピ データベースを設計しています。これは、テーブルに関してこれまでのところ私が持っているものです:

  • レシピ: このテーブルには、レシピの日付 (名前、調理に必要な手順など) が含まれます。
  • 材料/在庫: これは私たちの家の在庫であるため、レシピで使用される各製品に関する情報が含まれます.
  • レシピ ライン アイテム: これは扱いにくいテーブルです。ここの材料とレシピに必要な量にリンクできるようにしたいのですが、レシピ テーブルからレシピを直接含めることもできるようにする必要があります (マリナラ ソースなど)。そのため、このテーブルを設計する最善の方法を見つけるのに苦労しています.

基本的に、レシピ項目テーブルは、必要な項目に応じて材料テーブルまたはレシピ テーブルのいずれかにリンクできる必要があり、それを処理する最も効果的な方法を知りたいです。

よろしくお願いします!

4

5 に答える 5

8

次のようなデータベース モデルが必要なようです。

ここに画像の説明を入力

このモデルには次のプロパティがあります。

  • 基本的に、各レシピは一連のステップです。
  • 各ステップには、同じレシピ (STEP_NO)、単位 (質量、体積、カウント...)、その単位での量などの他のステップに対する相対的な順序があります。
  • 特定のステップは、材料 (INGREDIENT_ID が非 NULL の場合) または別のレシピ (SUBRECIPE_ID が非 NULL の場合) に接続されます。1
  • それ以外では、STEP は多対多の関係を実装するかなり標準的なジャンクション テーブルです。つまり、同じ材料を複数のレシピ (または同じレシピの複数のステップ) で使用でき、レシピを「サブ」にすることもできます。他の複数のレシピの -recipe」。
  • これは本質的に有向グラフです。データ モデル自体はサイクルを防止しません。サイクルはクライアント コード レベルで回避し、トリガーによって検出される可能性があります。

1 MySQL が CHECK 制約をサポートしている場合 (サポートしていない)、次のように、そのうちの 1 つ (両方ではない) が非 NULL であることを確認できます。

CHECK (
    (INGREDIENT_ID IS NULL AND SUBRECIPE_ID IS NOT NULL)
    OR (INGREDIENT_ID IS NOT NULL AND SUBRECIPE_ID IS NULL)
)

現状では、そのためのトリガーが必要になります。

于 2012-12-15T01:59:09.460 に答える
3

Ingredients両方ともRecipes可能RecipeItemsです:

CREATE TABLE RecipeItems (
  ItemID       SERIAL,
  Type         ENUM('Ingredient', 'Recipe'),
  Name         VARCHAR(255) NOT NULL,
  Quantity     FLOAT NOT NULL,
  INDEX (ItemID, Type)
);

CREATE TABLE Ingredients (
  IngredientID BIGINT UNSIGNED NOT NULL,
  Type         ENUM('Ingredient'),
  CostPrice    DECIMAL(6,2),
  PRIMARY KEY (IngredientID),
  FOREIGN KEY (IngredientID, Type) REFERENCES RecipeItems (ItemID, Type)
);

CREATE TABLE Recipes (
  RecipeID     BIGINT UNSIGNED NOT NULL,
  Type         ENUM('Recipe'),
  SellPrice    DECIMAL(6,2),
  Date         DATE,
  Instructions TEXT,
  PRIMARY KEY (RecipeID),
  FOREIGN KEY (RecipeID, Type) REFERENCES RecipeItems (ItemID, Type)
);

次にRecipeLineItems

CREATE TABLE RecipeLineItems (
  RecipeID     BIGINT UNSIGNED NOT NULL,
  ItemID       BIGINT UNSIGNED NOT NULL,
  Quantity     FLOAT NOT NULL,
  PRIMARY KEY (RecipeID, ItemID),
  FOREIGN KEY (RecipeID) REFERENCES Recipes     (RecipeID),
  FOREIGN KEY (ItemID)   REFERENCES RecipeItems (ItemID)
);

このアプローチでは、厳密な SQL モードを有効にすることをお勧めします (そうしないと、型指定された列で無効な値が受け入れられENUM、空の文字列''が特別なエラー値として受け入れられます): これにより、上記のモデルの意図した参照整合性が損なわれる可能性があります。別の (ただし少し面倒な) アプローチは、トリガーを使用して手動で参照整合性を強制することです。

MySQL だけがCHECK制約をサポートしていればよいでしょうか?

于 2012-12-14T16:56:57.107 に答える
1

このスクリプトは、レシピ、材料、レシピ構成(ingredients_recipes)を管理し、在庫と構成を統合するためのデータベースを作成します。また、在庫履歴を管理することもできます。

これがあなたの現在のレシピ、必要な材料、必要な量とあなたが現在持っている在庫を取得するためのクエリです:

SELECT recipes.id, recipes.name AS recipeName, ingredients.name AS ingredientNeeded, CONCAT(ingredients_recipes.Qty,' ',neededUnities.name) AS neededQuantity, CONCAT(inventories.qty,' ',inventoryUnities.name) AS availableQuantity FROM recipes 

LEFT JOIN ingredients_recipes ON recipes.id=ingredients_recipes.recipe_id 
LEFT JOIN ingredients ON ingredients_recipes.ingredient_id = ingredients.id 
LEFT JOIN inventories ON ingredients.id=inventories.ingredient_id 
LEFT JOIN unities AS inventoryUnities ON inventories.unity_id=inventoryUnities.id
LEFT JOIN unities AS neededUnities ON ingredients_recipes.unity_id=neededUnities.id

WHERE inventories.`update` = (SELECT MAX(`update`) FROM inventories AS inv WHERE inv.ingredient_id = inventories.ingredient_id);

データベース:

-- --------------------------------------------------------
-- Host:                         127.0.0.1
-- Server version:               5.5.16 - MySQL Community Server (GPL)
-- Server OS:                    Win32
-- HeidiSQL version:             7.0.0.4053
-- Date/time:                    2012-12-14 16:33:22
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET FOREIGN_KEY_CHECKS=0 */;

-- Dumping database structure for database
DROP DATABASE IF EXISTS `database`;
CREATE DATABASE IF NOT EXISTS `database` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `database`;


-- Dumping structure for table database.ingredients
DROP TABLE IF EXISTS `ingredients`;
CREATE TABLE IF NOT EXISTS `ingredients` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(250) NOT NULL,
  `unity_id` int(11) NOT NULL COMMENT 'for the default unity',
  `Created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `Unity_id` (`unity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table database.ingredients: ~0 rows (approximately)
DELETE FROM `ingredients`;
/*!40000 ALTER TABLE `ingredients` DISABLE KEYS */;
/*!40000 ALTER TABLE `ingredients` ENABLE KEYS */;


-- Dumping structure for table database.ingredients_recipes
DROP TABLE IF EXISTS `ingredients_recipes`;
CREATE TABLE IF NOT EXISTS `ingredients_recipes` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `ingredient_id` int(10) NOT NULL,
  `recipe_id` int(10) NOT NULL,
  `Qty` float NOT NULL,
  `Unity_id` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ingredient_id_recipe_id` (`ingredient_id`,`recipe_id`),
  KEY `Unity_id` (`Unity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table database.ingredients_recipes: ~0 rows (approximately)
DELETE FROM `ingredients_recipes`;
/*!40000 ALTER TABLE `ingredients_recipes` DISABLE KEYS */;
/*!40000 ALTER TABLE `ingredients_recipes` ENABLE KEYS */;


-- Dumping structure for table database.inventories
DROP TABLE IF EXISTS `inventories`;
CREATE TABLE IF NOT EXISTS `inventories` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `ingredient_id` int(10) NOT NULL COMMENT 'ingredient',
  `qty` int(10) NOT NULL COMMENT 'quantity',
  `unity_id` int(11) NOT NULL COMMENT 'unity for the ingredient',
  `update` datetime NOT NULL COMMENT 'date of the inventory update',
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table database.inventories: ~0 rows (approximately)
DELETE FROM `inventories`;
/*!40000 ALTER TABLE `inventories` DISABLE KEYS */;
/*!40000 ALTER TABLE `inventories` ENABLE KEYS */;


-- Dumping structure for table database.recipes
DROP TABLE IF EXISTS `recipes`;
CREATE TABLE IF NOT EXISTS `recipes` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(250) NOT NULL,
  `cooking` longtext NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table database.recipes: ~0 rows (approximately)
DELETE FROM `recipes`;
/*!40000 ALTER TABLE `recipes` DISABLE KEYS */;
/*!40000 ALTER TABLE `recipes` ENABLE KEYS */;


-- Dumping structure for table database.unities
DROP TABLE IF EXISTS `unities`;
CREATE TABLE IF NOT EXISTS `unities` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table database.unities: ~0 rows (approximately)
DELETE FROM `unities`;
/*!40000 ALTER TABLE `unities` DISABLE KEYS */;
/*!40000 ALTER TABLE `unities` ENABLE KEYS */;
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
于 2012-12-14T21:34:04.430 に答える
0

一方通行。

Dish
Key ID Name
1   1  Snails in Marinara Sauce
2   2  Marinara Sauce
3   3  Glass of Water


Ingredient
Key DISHID Name
1   NULL   Snail
2   NULL   Tomato
3   NULL   Onion
4   NULL   Evian
5   2      Marinara Sauce

Recipe
DishID IngredientKey Qty UOM
1      1             6   Each
1      5             3   TblSpoon
2      2             2   Each
2      3             1   Each
3      4             275 Millilitres

したがって、材料が料理である場合、レシピがあります。

OPからの質問の後に修正されました。これは、私の潜在的な回答にわずかな欠陥があることを示しています。

于 2012-12-14T17:05:42.970 に答える
0

recipesテーブル、ingredientsテーブル、およびrecipe_ingredients材料をレシピに割り当てるテーブルの 3 つのテーブルが必要です。このテーブルには、数量などの追加情報を格納することもできます。たとえば、野菜スープのレシピがある場合、対応する量の野菜のエントリが複数あることになります。これらのエントリは、外部キーを介して関連するレシピと材料にリンクされます。

編集:最も単純なスキーマ:

CREATE TABLE `ingredients` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) TYPE=InnoDB;

CREATE TABLE `recipes` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) TYPE=InnoDB;

CREATE TABLE `recipe_ingredients` (
  `recipe_id` int(10) unsigned NOT NULL,
  `ingredient_id` int(10) unsigned NOT NULL,
  `quantity` int(10) unsigned NOT NULL,
  KEY `recipe_id` (`recipe_id`),
  KEY `ingredient_id` (`ingredient_id`)
) TYPE=InnoDB;


ALTER TABLE `recipe_ingredients`
  ADD CONSTRAINT `recipe_ingredients_ibfk_2` FOREIGN KEY (`ingredient_id`) REFERENCES `ingredients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `recipe_ingredients_ibfk_1` FOREIGN KEY (`recipe_id`) REFERENCES `recipes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
于 2012-12-14T16:41:37.320 に答える