我正在设计一个需要非常灵活的配方数据库,因为它将直接与我们的后台库存系统进行通信。这是我到目前为止关于表格的内容:
基本上,配方行项目表需要能够链接到配料表或配方表,具体取决于需要哪个行项目,我想知道最有效的方法是什么。
提前非常感谢你!
答案 0 :(得分:7)
看起来您需要一个类似于此的数据库模型:
此模型具有以下属性:
1 如果MySQL支持CHECK约束(它为doesn't),你可以确保它们中的一个(但不是两个)非NULL,如下所示:
CHECK (
(INGREDIENT_ID IS NULL AND SUBRECIPE_ID IS NOT NULL)
OR (INGREDIENT_ID IS NOT NULL AND SUBRECIPE_ID IS NULL)
)
目前,你需要一个触发器。
答案 1 :(得分: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
个约束,那么?
答案 2 :(得分:1)
此脚本将为您创建一个数据库,您可以使用该数据库管理食谱,成分,收件人组成(成分_食谱)以及库存和组合的统一性。它还可以让您管理库存历史记录。
以下是获取当前食谱,所需原料,所需数量和目前库存的查询:
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 */;
答案 3 :(得分:0)
您需要三个表:一个recipes
表,一个ingredients
表和一个recipe_ingredients
表,用于为配方分配成分。您还可以在此表中存储其他信息,例如数量。因此,例如,如果您有蔬菜汤的配方,您将有多个具有相应数量的蔬菜条目。然后,这些条目将通过外键链接到相关的配方和成分。
编辑:最简单的架构:
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;
答案 4 :(得分: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的一个问题之后修改,这指出了我的潜在答案中的一个小问题。