Я пишу приложение к материалам/рецепту для Minecraft в Node.js, Express, React и MySQL.
У меня есть то, что я считаю хорошей структурой для базы данных с таблицами, но у меня возникает проблема с запросами, которые мне нужно запустить. Вот пример того, что я пытаюсь сделать с примером вывода (я знаю, что рецепт неправильный MC игроков).
Таблица ингредиентов:
RECIPE || INGREDIENT || QTY || TYPE
Piston || Redstone || 1 || RM
Piston || Iron Ingot || 1 || RM
Piston || Wood Planks || 3 || RM
Piston || Stone || 4 || RM
Sticky Piston || Piston || 2 || CO
Sticky Piston || Slimeball || 1 || RM
Я хочу, чтобы при запросе на Sticky Piston была возвращена таблица со всеми необходимыми компонентами, суммированными вместе (сверху) и всеми необходимыми исходными материалами, суммированными вместе (ниже).
Пример Требуемый вывод в формате таблицы или формате JSON:
INGREDIENT || QTY || TYPE
Piston || 2 || CO
Redstone || 2 || RM
Iron Ingot || 2 || RM
Wood Planks || 6 || RM
Stone || 8 || RM
Slimeball || 1 || RM
[
{
"Ingredient": "Piston",
"Qty": 2,
"Type": CO
},
{
"Ingredient": "Redstone",
"Qty": 2,
"Type": RM
},
{
"Ingredient": "Iron Ingot",
"Qty": 2,
"Type": RM
},
{
"Ingredient": "Wood Planks",
"Qty": 6,
"Type": RM
},
{
"Ingredient": "Stone",
"Qty": 8,
"Type": RM
},
{
"Ingredient": "Slimeball",
"Qty": 2,
"Type": RM
}
]
Я предполагаю, что это ПРИСОЕДИНИТЕСЬ с некоторыми другими причудливыми вещами, которые могут делать все это внутри синтаксиса MYSQL, но я не могу понять это, несмотря на два дня опробовать разные комбинации.
В качестве альтернативы, было бы замечательно, если бы вместо использования синтаксиса MYSQL этот JS использовался, чтобы я мог запускать его на моем сервере Node.js.
Ниже приведена модифицированная версия схемы по инструкциям ниже. Это то, чем должно быть мое понимание отношений, но я до сих пор не могу понять, как вернуть все необходимые ресурсы, когда рецепты состоят из других компонентов, для которых требуются и другие Материалы.
CREATE TABLE Ingredients
(
MaterialID INT unsigned NOT NULL AUTO_INCREMENT,
Material VARCHAR(250) NOT NULL,
MaterialImage VARCHAR(250),
PRIMARY KEY (MaterialID)
);
CREATE TABLE Recipes
(
RecipeID INT unsigned NOT NULL AUTO_INCREMENT,
Recipe VARCHAR(250) NOT NULL,
PRIMARY KEY (ComponentID)
);
CREATE TABLE Recipes_Ingredients
(
RecipeID INT unsigned NOT NULL,
MaterialID INT unsigned NOT NULL,
Quantity INT unsigned NOT NULL
)
Спасибо!
UPDATE/EDIT:
Обновлен для правильного расчета количества
Я изменил расположение таблицы, чтобы лучше сопоставлять данные, которые вы пытаетесь представить. Поскольку "рецепт" также может быть "материалом", я удалил таблицу рецептов и сохранил эти данные в таблице материалов.
Я также создал SQL Fiddle, чтобы вы могли играть с запросом и точно настраивать результаты.
Первый запрос ниже возвращает все "рецепты" и их компоненты. Чтобы получить только один конкретный рецепт, просто добавьте условие в предложение where, которое выбирает конкретный рецепт.
Если вы предпочитаете иметь компоненты, перечисленные в одном поле, с одной строкой в каждом рецепте, вы можете использовать функцию GROUP_CONCAT и изменить предложение group by.
Второй запрос ниже показывает функцию GROUP_CONCAT. Он также показывает, как изменить недостающие суб-ингредиенты от NULL до "Нет"
MySQL 5.6 Настройка схемы:
CREATE TABLE 'Ingredients'
(
'MaterialID' INT unsigned NOT NULL AUTO_INCREMENT,
'Material' VARCHAR(250) NOT NULL,
'MaterialImage' VARCHAR(250),
'IsRecipe' TINYINT(1) DEFAULT 0 NULL,
PRIMARY KEY ('MaterialID')
);
CREATE TABLE 'Recipes_Ingredients'
(
'id' INT unsigned NOT NULL AUTO_INCREMENT,
'RecipeID' INT unsigned NOT NULL,
'MaterialID' INT unsigned NOT NULL,
'Quantity' INT unsigned NOT NULL,
PRIMARY KEY ('id')
);
INSERT INTO 'Ingredients'
('MaterialID','Material','MaterialImage','IsRecipe')
VALUES
(1,'Redstone','redstone.jpg',0),
(2,'Iron Ingot','ironingot.jpg',0),
(3,'Wood Planks','woodplanks.jpg',0),
(4,'Stone','stone.jpg',0),
(5,'Slimeball','slimeball.jpg',0),
(6,'Piston','piston.jpg',1),
(7,'Sticky Piston','stickypiston.jpg',1),
(8,'Sticky Piston 2','stickypiston2.jpg',1);
INSERT INTO 'Recipes_Ingredients'
('RecipeID','MaterialID','Quantity')
VALUES
(6,1,1),
(6,2,1),
(6,3,3),
(6,4,4),
(7,6,1),
(7,5,1),
(8,6,2),
(8,5,1);
Запрос 1:
SELECT
a.'MaterialID',
c.'MaterialID',
a.'Material' as 'Recipe',
a.'MaterialImage' as 'RecipeImage',
c.'Material' as 'Ingredient',
b.'Quantity' as 'FirstIngredientQuantity',
c.'MaterialImage' as 'IngredientImage',
IF(d.'Quantity' IS NULL,SUM(b.'Quantity'),COALESCE(d.'Quantity',0)*b.'Quantity') as 'Quantity',
e.'Material' as 'Ingredient',
e.'MaterialImage' as 'MaterialImage'
FROM 'Ingredients' a
LEFT JOIN 'Recipes_Ingredients' b
ON b.'RecipeID' = a.'MaterialID'
LEFT JOIN 'Ingredients' c
ON c.'MaterialID' = b.'MaterialID'
LEFT JOIN 'Recipes_Ingredients' d
ON d.'RecipeID' = c.'MaterialID'
LEFT JOIN 'Ingredients' e
ON e.'MaterialID' = d.'MaterialID' AND c.'IsRecipe' = 1
WHERE a.'IsRecipe' = 1 AND a.'MaterialID' in (7,8)
GROUP BY a.'MaterialID',c.'MaterialID',e.'MaterialID'
| MaterialID | MaterialID | Recipe | RecipeImage | Ingredient | FirstIngredientQuantity | IngredientImage | Quantity | Ingredient | MaterialImage |
|------------|------------|-----------------|-------------------|------------|-------------------------|-----------------|----------|-------------|----------------|
| 7 | 5 | Sticky Piston | stickypiston.jpg | Slimeball | 1 | slimeball.jpg | 1 | (null) | (null) |
| 7 | 6 | Sticky Piston | stickypiston.jpg | Piston | 1 | piston.jpg | 1 | Redstone | redstone.jpg |
| 7 | 6 | Sticky Piston | stickypiston.jpg | Piston | 1 | piston.jpg | 1 | Iron Ingot | ironingot.jpg |
| 7 | 6 | Sticky Piston | stickypiston.jpg | Piston | 1 | piston.jpg | 3 | Wood Planks | woodplanks.jpg |
| 7 | 6 | Sticky Piston | stickypiston.jpg | Piston | 1 | piston.jpg | 4 | Stone | stone.jpg |
| 8 | 5 | Sticky Piston 2 | stickypiston2.jpg | Slimeball | 1 | slimeball.jpg | 1 | (null) | (null) |
| 8 | 6 | Sticky Piston 2 | stickypiston2.jpg | Piston | 2 | piston.jpg | 2 | Redstone | redstone.jpg |
| 8 | 6 | Sticky Piston 2 | stickypiston2.jpg | Piston | 2 | piston.jpg | 2 | Iron Ingot | ironingot.jpg |
| 8 | 6 | Sticky Piston 2 | stickypiston2.jpg | Piston | 2 | piston.jpg | 6 | Wood Planks | woodplanks.jpg |
| 8 | 6 | Sticky Piston 2 | stickypiston2.jpg | Piston | 2 | piston.jpg | 8 | Stone | stone.jpg |
Запрос 2:
SELECT
a.'MaterialID',
c.'MaterialID',
a.'Material' as 'Recipe',
a.'MaterialImage' as 'RecipeImage',
c.'Material' as 'Ingredient',
c.'MaterialImage' as 'MaterialImage',
SUM(b.'Quantity' + COALESCE(d.'Quantity',0)) as 'Quantity',
COALESCE(GROUP_CONCAT(CONCAT(e.'Material',' (',b.'Quantity' * d.'Quantity',') [',e.'MaterialImage',']')),'None') as 'Ingredients'
FROM 'Ingredients' a
LEFT JOIN 'Recipes_Ingredients' b
ON b.'RecipeID' = a.'MaterialID'
LEFT JOIN 'Ingredients' c
ON c.'MaterialID' = b.'MaterialID'
LEFT JOIN 'Recipes_Ingredients' d
ON d.'RecipeID' = c.'MaterialID'
LEFT JOIN 'Ingredients' e
ON e.'MaterialID' = d.'MaterialID' AND c.'IsRecipe' = 1
WHERE a.'IsRecipe' = 1
GROUP BY a.'MaterialID',c.'MaterialID'
| MaterialID | MaterialID | Recipe | RecipeImage | Ingredient | MaterialImage | Quantity | Ingredients |
|------------|------------|-----------------|-------------------|-------------|----------------|----------|-------------------------------------------------------------------------------------------------------------------|
| 6 | 1 | Piston | piston.jpg | Redstone | redstone.jpg | 1 | None |
| 6 | 2 | Piston | piston.jpg | Iron Ingot | ironingot.jpg | 1 | None |
| 6 | 3 | Piston | piston.jpg | Wood Planks | woodplanks.jpg | 3 | None |
| 6 | 4 | Piston | piston.jpg | Stone | stone.jpg | 4 | None |
| 7 | 5 | Sticky Piston | stickypiston.jpg | Slimeball | slimeball.jpg | 1 | None |
| 7 | 6 | Sticky Piston | stickypiston.jpg | Piston | piston.jpg | 13 | Redstone (1) [redstone.jpg],Iron Ingot (1) [ironingot.jpg],Wood Planks (3) [woodplanks.jpg],Stone (4) [stone.jpg] |
| 8 | 5 | Sticky Piston 2 | stickypiston2.jpg | Slimeball | slimeball.jpg | 1 | None |
| 8 | 6 | Sticky Piston 2 | stickypiston2.jpg | Piston | piston.jpg | 17 | Redstone (2) [redstone.jpg],Iron Ingot (2) [ironingot.jpg],Wood Planks (6) [woodplanks.jpg],Stone (8) [stone.jpg] |