Storing multivalued attributes in a single comma separated field is almost always a bad idea. It makes everything very difficult to query.
Instead, you may want to consider refactoring your schema, using two new intersection tables.
These two tables remain as they are (just changed name of recipe_category
to categories
in order not to clash with the intersection table):
CREATE TABLE categories (
cid int NOT NULL PRIMARY KEY,
category_name varchar(50)
) ENGINE=INNODB;
CREATE TABLE ingredients (
iid int NOT NULL PRIMARY KEY,
ingredient_name varchar(50)
) ENGINE=INNODB;
Modify the recipe_name
table as follows, removing the cid
and iid
fields:
CREATE TABLE recipe_name (
id int NOT NULL PRIMARY KEY,
recipe_name varchar(50)
) ENGINE=INNODB;
Then you can define your multivalued relationships using the following two intersection tables:
CREATE TABLE recipe_ingredients (
recipe_id int NOT NULL,
ingredient_id int NOT NULL,
PRIMARY KEY (recipe_id, ingredient_id),
FOREIGN KEY (recipe_id) REFERENCES recipe_name (id),
FOREIGN KEY (ingredient_id) REFERENCES ingredients (iid)
) ENGINE=INNODB;
CREATE TABLE recipe_categories (
recipe_id int NOT NULL,
category_id int NOT NULL,
PRIMARY KEY (recipe_id, category_id),
FOREIGN KEY (recipe_id) REFERENCES recipe_name (id),
FOREIGN KEY (category_id) REFERENCES categories (cid)
) ENGINE=INNODB;
Now let's populate these tables with your example data:
INSERT INTO categories VALUES (1, 'desserts');
INSERT INTO categories VALUES (2, 'cakes');
INSERT INTO categories VALUES (3, 'biscuits');
INSERT INTO ingredients VALUES(1, 'self-raising flour');
INSERT INTO ingredients VALUES(2, 'milk');
INSERT INTO ingredients VALUES(3, 'chocolate');
INSERT INTO ingredients VALUES(4, 'baking powder');
INSERT INTO ingredients VALUES(5, 'plain flour');
INSERT INTO recipe_name VALUES(1, 'black forest cake');
INSERT INTO recipe_name VALUES(2, 'angel cake');
INSERT INTO recipe_name VALUES(3, 'melting moments');
INSERT INTO recipe_name VALUES(4, 'croquembouche');
To define the relationships between the recipes and their ingredients and categories, you would need to fill up the intersection tables as follows:
INSERT INTO recipe_categories VALUES (1, 1);
INSERT INTO recipe_categories VALUES (1, 2);
INSERT INTO recipe_categories VALUES (2, 2);
INSERT INTO recipe_categories VALUES (3, 3);
INSERT INTO recipe_categories VALUES (4, 1);
INSERT INTO recipe_categories VALUES (4, 3);
INSERT INTO recipe_ingredients VALUES (1, 1);
INSERT INTO recipe_ingredients VALUES (1, 2);
INSERT INTO recipe_ingredients VALUES (1, 3);
INSERT INTO recipe_ingredients VALUES (1, 4);
INSERT INTO recipe_ingredients VALUES (2, 1);
INSERT INTO recipe_ingredients VALUES (2, 2);
INSERT INTO recipe_ingredients VALUES (2, 3);
INSERT INTO recipe_ingredients VALUES (3, 2);
INSERT INTO recipe_ingredients VALUES (3, 5);
INSERT INTO recipe_ingredients VALUES (4, 1);
INSERT INTO recipe_ingredients VALUES (4, 5);
Finally, building your query will be as easy as this:
SELECT i.ingredient_name
FROM recipe_ingredients ri
JOIN ingredients i ON (i.iid = ri.ingredient_id)
WHERE ri.recipe_id = (SELECT id
FROM recipe_name
WHERE recipe_name = 'Black Forest Cake');
Result:
+--------------------+
| ingredient_name |
+--------------------+
| self-raising flour |
| milk |
| chocolate |
| baking powder |
+--------------------+
4 rows in set (0.00 sec)
You may then want to format that result set (adding the <br>
s) in your application code instead of in SQL.
However if you really wish to do that in SQL, then MySQL supports the handy GROUP_CONCAT()
function, which can be used as follows:
SELECT GROUP_CONCAT(i.ingredient_name separator '<BR>') output
FROM recipe_ingredients ri
JOIN ingredients i ON (i.iid = ri.ingredient_id)
WHERE ri.recipe_id = (SELECT id
FROM recipe_name
WHERE recipe_name = 'Black Forest Cake');
Result:
+----------------------------------------------------------+
| output |
+----------------------------------------------------------+
| self-raising flour<BR>milk<BR>chocolate<BR>baking powder |
+----------------------------------------------------------+
1 row in set (0.00 sec)
Dump that into HTML, and you're good to go!