Question

I've been working on a food recipe database for a while now and i have accumulated a few questions about my design. This is my first project so if you see something strange, please point it out. Here's what i have sofar:

The table below is a list of words like "decilitre, litre, dozen" etc.

CREATE TABLE amount_type(
    amount_type_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    amount_type VARCHAR(40) NOT NULL,
    PRIMARY KEY (amount_type_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

This below keeps track of recipe name, a description: "good ol' pancakes", all instructions "add eggs, flour, milk into frying pan" and the amount of food created.

CREATE TABLE recipe(
    recipe_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    description VARCHAR(100) NOT NULL,
    instruction VARCHAR (250) NOT NULL,
    amount SMALLINT(10) UNSIGNED NOT NULL,
    amount_type_id INT(10) UNSIGNED NOT NULL,   
    last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (amount_type_id) REFERENCES amount_type (amount_type_id),
    PRIMARY KEY (recipe_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

Each ingredient belongs to a type like "vegetable, dairy-product"

CREATE TABLE ingredient_type(
    ingredient_type_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    type VARCHAR(40) NOT NULL,
    PRIMARY KEY (ingredient_type_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

Which company produced the ingredient:

CREATE TABLE ingredient_brand(
    ingredient_brand_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    brand_name VARCHAR(40) NOT NULL,
    PRIMARY KEY (ingredient_brand_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

ingredient name, description of ingredient, unit_price is per litre/kilo depending on product, temporary discount prices.

CREATE TABLE ingredient(
    ingredient_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    ingredient_type_id INT(10) UNSIGNED NOT NULL,
    name VARCHAR(40) NOT NULL,
    description VARCHAR(40) NOT NULL,
    ingredient_brand_id INT(10) UNSIGNED NOT NULL,
    unit_price DECIMAL(9,4) UNSIGNED NOT NULL,
    unit_discount_price DECIMAL(9,4) UNSIGNED NOT NULL,
    unit_discount_expire_date DATE NOT NULL,
    last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (ingredient_type_id) REFERENCES ingredient_type (ingredient_type_id),
    FOREIGN KEY (ingredient_brand_id) REFERENCES ingredient_brand (ingredient_brand_id),
    PRIMARY KEY (ingredient_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

Relational table between recipe and ingredient that also tracks amounts of ingredients in each recipe.

CREATE TABLE recipe_to_ingredient(
    recipe_id INT(10) UNSIGNED NOT NULL,
    ingredient_id INT(10) UNSIGNED NOT NULL,
    amount DECIMAL(9,2) UNSIGNED NOT NULL, 
    amount_type_id INT(10) UNSIGNED NOT NULL,
    FOREIGN KEY (recipe_id) REFERENCES recipe (recipe_id),
    FOREIGN KEY (ingredient_id) REFERENCES ingredient (ingredient_id),
    FOREIGN KEY (amount_type_id) REFERENCES amount_type (amount_type_id),
    PRIMARY KEY (recipe_id, ingredient_id)
)
ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_swedish_ci;

Now for the questions: Some ingredients like tap water do not belong to a brand or a given price. And sometimes discount prices and discount date is not stored either due to it not being available at that point in time.

How would you deal with that? Is the fault in the design? Should i store a value like "undefined". Should i allow those fields to be null? When it comes to price, most products (99% and above) probably have prices after all.

There is also the problem atm that the cheapest ingredient might be a 5 litre container when all you need is 2 decilitre. But i can live with that since it seems kind of hard to compensate for it atm.

Any input/suggestions are appreciated!

Was it helpful?

Solution

The price of water is known (at least in the first world), so I would use $0.00 over NULL. Since you're not joining to another table based on this column, there's no problem with having a mix of values and NULLs.

ingredient_brand is harder, since you do want to join based on this column. There really is no brand, so I'd use NULL (thus requiring an OUTER JOIN).

As for buying in bulk, you could give the user an option in their profile to allow that ("if I can save x%..."). You might also want to figure out whether the product has a long shelf life before buying in bulk.

Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top