Вывод данных из таблиц mysql - PullRequest
2 голосов
/ 19 июля 2010

recipe_category

cid | category
 1  | desserts
 2  | cakes
 3  | biscuits

recipe_name

id | recipe_name       | cid | iid
 1 | black forest cake | 1,2 | 1,2,3,4
 2 | angel cake        | 2   | 1,2,4
 3 | melting moments   | 3   | 2,5
 4 | croquembouche     | 1,3 | 1,5

ингредиенты

iid | ingredient_name
 1  | self-raising flour
 2  | milk
 3  | chocolate
 4  | baking powder
 5  | plain flour

Я могу сделать запрос к БД, используя cid, чтобы получить определенные рецепты, т.е. десерты:

SELECT * FROM recipe_name WHERE cid='1'

Но тогда как мне создать список ингредиентов, как показано ниже, где ингредиенты перечислены с <br>?

Шварцвальдский пирог:
Саморазвивающаяся мука
Молоко
Шоколад
Разрыхлитель

Я новичок в этом, поэтому, пожалуйста, прости любые глупые вопросы!

Ответы [ 4 ]

5 голосов
/ 19 июля 2010

Хранение многозначных атрибутов в одном поле, разделенном запятыми, почти всегда является плохой идеей. Это делает все очень сложным для запроса.

Вместо этого вы можете рассмотреть возможность рефакторинга вашей схемы с использованием двух новых таблиц пересечений.

Эти две таблицы остаются без изменений (просто измените имя 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, и все готово!

1 голос
/ 19 июля 2010

Вы определенно не хотите иметь список внешних ключей через запятую, как вы сделали с cid и iid в recipe_name. Вместо этого создайте таблицы, которые просто обрабатывают эти отношения:

recipe_name

id | recipe_name
 1 | black forest cake
 2 | angel cake
 3 | melting moments
 4 | croquembouche

recipe_categories

id | cid
 1 |  1
 1 |  2
 2 |  2
 3 |  3
 4 |  1
 4 |  3

recipe_ingredients

id | iid
 1 |  1
 1 |  2
 1 |  3
 1 |  4
 2 |  1
 2 |  2
 2 |  4
 3 |  2
 3 |  5
 4 |  1
 4 |  5

Теперь ваш запрос выбора любых десертов (ваш старый не работал, так как он пропустил бы строки с cid 1,2, например) выглядит следующим образом:

SELECT recipe_name.* FROM recipe_name, recipe_categories WHERE recipe_name.id = recipe_categories.id AND recipe_categories=cid = 1;

Как только вы это сделаете, вы можете написать запрос, который объединит таблицы ingredients и recipe_ingredients, чтобы получить желаемые результаты:

SELECT ingredients.* FROM ingredients, recipe_ingredients WHERE recipe_ingredients.id = 1 AND recipe_ingredients.iid = ingredients.iid;
1 голос
/ 19 июля 2010

Прежде всего вы должны использовать таблицу пересечений. В этой таблице у вас будет список ключей для recipe_names и ключ для каждого из ингредиентов. Таким образом, для шварцвальдского торта у вас будет 4 строки в таблице пересечений. Это позволяет создавать запросы намного быстрее и проще. Вам не нужно возиться с массивами клавиш.

Стол для шварцвальдского пирога может выглядеть следующим образом:

recipe_name_id  ingredients_id
1                 1
1                 2
1                 3
1                 4

Запрос будет выглядеть так:

SELECT ingredient_name
  FROM recipe_name
     , ingredients
     , recipe_ingredients --intersect table
 WHERE recipe_name.id=1
   AND recipe_name.id = recipe_ingredients.recipe_name_id
   AND ingredients.id = recipe_ingredients.ingredients_id
0 голосов
/ 19 июля 2010

Тот факт, что вы спрашиваете о <br>, говорит мне, что вы хотите отобразить их на веб-странице. Мой совет - отделить запрос данных от их отображения.

Поскольку в рецепте может быть много ингредиентов, а ингредиент может присутствовать во многих рецептах, между рецептом и ингредиентом вам понадобится таблица соединения многих-многих. Он будет иметь два столбца - один для первичного ключа рецепта, а другой для первичного ключа ингредиента.

Ваши значения через запятую нарушают правила нормализации . Вы хотите знать, что это такое.

...