Como estruturar uma base de dados com várias tabelas de junção
o objectoda receita quero armazenar e regenerar a partir da base de Dados
{
"id": 2345,
"name": "cake",
"description": "yummy cake",
"categorys": [
17,
26
],
"persons": 4,
"author": 26,
"language": "de",
"unit": "en",
"variantOf": 34,
"specialTools": [
34,
44,
10
],
"img": "32598734.jpg",
"estTime": 2777,
"steps": {
"1": {
"title": "mix",
"description": "mix all together",
"img": "45854.jpg",
"timer": null,
"ingredients": [
{
"name": "Butter",
"color": "#227799",
"amount": 150,
"unit": "g"
},
{
"name": "egg",
"color": "#aaff22",
"amount": 3,
"unit": "pc"
},
{
"name": "sugar",
"color": "#22ffff",
"amount": 50,
"unit": "g"
}
]
},
"2": {
"title": "bake",
"description": "put it in the oven",
"img": null,
"timer": 2400,
"ingredients": [
{
"name": "butter",
"color": "#227799",
"amount": null,
"unit": null
},
{
"name": "sugar",
"color": "#22ffff",
"amount": null,
"unit": null
},
{
"name": "egg",
"color": "#aaff22",
"amount": null,
"unit": null
}
]
}
}
}
a parte mais complexa é o objecto steps
. Cada receita pode ter um número variado de passos com diferentes ingredientes atribuídos a cada setp.
Aqui está uma base de Dados que eu fiz
recipe_id, step_id
são estrangeiros chave. Eu quero tudo em tabelas diferentes, porque as receitas devem ser sentáveis por ingredientes, categorias...
código SQL para gerar as tabelas mais importantes
-- ----------------------------------------------------- -- Table `dev_Recipe`.`recipe` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `dev_Recipe`.`recipe` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NULL , `description` TEXT NULL , `author_id` INT UNSIGNED NOT NULL , PRIMARY KEY (`id`) , INDEX `author_id_idx` (`author_id` ASC) , CONSTRAINT `author_id` FOREIGN KEY (`author_id` ) REFERENCES `dev_Recipe`.`users` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `dev_Recipe`.`step` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `dev_Recipe`.`step` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `recipe_id` INT UNSIGNED NOT NULL , `step_number` INT UNSIGNED NOT NULL , `description` TEXT NULL , `timer` INT UNSIGNED NULL , `image` VARCHAR(100) NULL , PRIMARY KEY (`id`) , INDEX `recipe_id_idx` (`recipe_id` ASC) , CONSTRAINT `step_recipe_id` FOREIGN KEY (`recipe_id` ) REFERENCES `dev_Recipe`.`recipe` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `dev_Recipe`.`ingredient` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `dev_Recipe`.`ingredient` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `name` VARCHAR(45) NOT NULL , `color` INT NOT NULL , `img` VARCHAR(45) NULL , PRIMARY KEY (`id`) ) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `dev_Recipe`.`step_ingredients` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `dev_Recipe`.`step_ingredients` ( `recipe_id` INT UNSIGNED NOT NULL , `ingredient_id` INT UNSIGNED NOT NULL , `step_id` INT UNSIGNED NOT NULL , `amount` INT NULL , `unit` VARCHAR(25) NULL , INDEX `recipe_id_idx` (`recipe_id` ASC) , INDEX `ingredient_id_idx` (`ingredient_id` ASC) , INDEX `step_id_idx` (`step_id` ASC) , PRIMARY KEY (`recipe_id`, `step_id`) , CONSTRAINT `step_ing_recipe_id` FOREIGN KEY (`recipe_id` ) REFERENCES `dev_Recipe`.`recipe` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `ingredient_step_ing_id` FOREIGN KEY (`ingredient_id` ) REFERENCES `dev_Recipe`.`ingredient` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `step_ing_id` FOREIGN KEY (`step_id` ) REFERENCES `dev_Recipe`.`step` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB;Uma vez que nunca me tinha juntado a Mesas, não sei se essa é a abordagem certa para o meu problema. É um design reasonalbe e como otimizá-lo?
eu fiz outro desenho, onde recipes
está unido com step
e step
com ingredients
.
Eu acho que o primeiro layout é mais fácil de consultar, porque posso procurar por ingredients_id
recipe_id
só olhando para step_ingredients
, mas não tenho a certeza. Alguma ideia?
2 answers
A principal coisa com o desenho da base de dados relacional é que existem 3 tipos de relações FK:
- 1 a 1
- 1 a muitos
- muitos a muitos
Algumas notas:
Um ingrediente de passo necessita de um passo que já tenha um recipe_ ID (possivelmente nulo)
Pode Existir Um ingrediente de passo sem um passo
Pode Existir Um passo sem uma receita
O Utilizador da receita é um para um (como Dan mencionado)
Editar: Para a preocupação com a dupla junção em vez de uma única junção para ir de receita para Ingrediente, aqui está uma preocupação de normalização que eu duro com o projeto original: o que mantém o step_ingredient e Step recipe_ ID é o mesmo? Neste momento, não haveria garantia de consistência. Se você considerar o projeto de dados você está realmente dizendo que você acha que vai se juntar muito a estas duas mesas, então por que não conectá-las com um FK desnecessário (não faça isso ou as coisas vão ficar confusas rapidamente:)
O seu segundo desenho também permite o mesmo número de junções porque incluiu o recipe_id como um PK na tabela passo que se torna um PK/FK no step_ingredient e irá garantir consistência recipe_id. ex:
SELECT ingredient_id
FROM Recipe r
JOIN Step_ingredient si on si.step_recipe_id = r.recipe_id
JOIN Ingredient i on si.ingredient_id = i.ingredient_id
E o meu link favorito para começar com a normalização de bases de dados: http://en.wikipedia.org/wiki/Database_normalization
Além disso, você vai precisar de muitas a muitas relações entre usuários e receitas. Você tem o que parece um para um.