Como estruturar uma base de dados com várias tabelas de junção

É a primeira vez que tento armazenar um objecto mais complexo numa base de dados. Preciso de ajuda com o desenho da base de dados.

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 database scheme

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?

database design 2

Author: Akkumulator, 2013-04-12

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
Dito isto, o seu esquema parece bem normalizado e lógico num piscar de olhos. A única cautela que eu colocaria é que a recursão pode ser complicada em SQL para as categorias com referências próprias.

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
 5
Author: munch1324, 2013-04-13 12:50:58
À primeira vista parece muito bom. No entanto, Não tenho certeza por que as tabelas de categoria e categoria de ingredientes precisam de identificações pais.

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.

 2
Author: Dan Bracuk, 2013-04-12 12:56:42