Хранение многозначных атрибутов в одном поле, разделенном запятыми, почти всегда является плохой идеей. Это делает все очень сложным для запроса.
Вместо этого вы можете рассмотреть возможность рефакторинга вашей схемы с использованием двух новых таблиц пересечений.
Эти две таблицы остаются без изменений (просто измените имя recipe_category
на categories
, чтобы не конфликтовать с таблицей пересечений):
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;
Измените таблицу recipe_name
следующим образом, удалив поля cid
и iid
:
CREATE TABLE recipe_name (
id int NOT NULL PRIMARY KEY,
recipe_name varchar(50)
) ENGINE=INNODB;
Затем вы можете определить ваши многозначные отношения, используя следующие две таблицы пересечений:
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;
Теперь давайте заполним эти таблицы данными вашего примера:
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');
Чтобы определить отношения между рецептами и их ингредиентами и категориями, вам необходимо заполнить таблицы пересечений следующим образом:
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);
Наконец, создание вашего запроса будет так же просто, как это:
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');
Результат:
+--------------------+
| ingredient_name |
+--------------------+
| self-raising flour |
| milk |
| chocolate |
| baking powder |
+--------------------+
4 rows in set (0.00 sec)
Затем вы можете отформатировать этот набор результатов (добавив <br>
s) в код своего приложения, а не в SQL.
Однако, если вы действительно хотите сделать это в SQL, MySQL поддерживает удобную функцию GROUP_CONCAT()
, которую можно использовать следующим образом:
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');
Результат:
+----------------------------------------------------------+
| output |
+----------------------------------------------------------+
| self-raising flour<BR>milk<BR>chocolate<BR>baking powder |
+----------------------------------------------------------+
1 row in set (0.00 sec)
Добавьте это в HTML, и все готово!