Запрос MySQL с несколькими соединениями, возвращающими несколько повторяющихся результатов

Я пытаюсь запросить 4 таблицы.

Вот таблицы:

рецепты - содержит все рецепты

recipe_steps - шаги приготовления по рецептам (с 1 по м)

ингредиенты_на_рецептах — таблица соединения m с m, содержащая идентификатор рецепта и идентификатор ингредиента (от m к m)

ингредиенты - содержит все ингредиенты (от 1 до m)

Проблема, с которой я сталкиваюсь, заключается в том, что я возвращаю 65 строк, когда я должен получить только 18.

Вот мой запрос MySQL:

SELECT r.id, rs.id, i.id FROM recipes r
  JOIN recipe_steps rs ON rs.recipe_id = r.id
  JOIN ingredients_on_recipes ior ON ior.recipeId = r.id
  JOIN ingredients i ON i.id = ior.ingredientId
WHERE r.id = 19

Когда я использую следующий запрос:

SELECT r.id, rs.id FROM recipes r
  JOIN recipe_steps rs ON rs.recipe_id = r.id
WHERE r.id = 19

Я получаю 5 строк, как и ожидалось.

Когда я использую следующий запрос:

SELECT r.id, i.id FROM recipes r
  JOIN ingredients_on_recipes ior ON ior.recipeId = r.id
  JOIN ingredients i ON i.id = ior.ingredientId
WHERE r.id = 19

Я получаю 13 строк, как и ожидалось.

Но когда я использую в одном запросе и recipe_steps, и ингредиенты, я получаю 65 строк с множеством дубликатов ингредиентов и шагов.

Я также попытался добавить:

GROUP BY r.id, rs.id, i.id

Но опять же это возвращает 65 строк вместо 18.

Глядя на возвращаемые строки, кажется, что происходит то, что шаги (1,2,3,4,5) возвращают 1 для всех 13 строк ингредиентов, затем 2 и повторяют 13 строк ингредиентов и так далее до 5-го. шаг.

Примеры данных помогут ответить на ваш вопрос.

Tim Biegeleisen 10.04.2022 10:12

Привет @TimBiegeleisen, хорошо, спасибо, я добавлю данные. Кажется, что происходит то, что шаги (которые должны быть 1,2,3,4,5) показывают 1 для всех 13 ингредиентов, затем 2 для всех 13 ингредиентов и так далее. У вас есть идеи, почему это может быть?

herbie 10.04.2022 10:21

Если у вас есть один рецепт с 10 шагами, он вернет рецепт 10 раз с шагами. Вы должны разбить запрос, сначала получить рецепты, а затем для каждого рецепта получить шаги.

Grumpy 10.04.2022 10:32

Спасибо @Grumpy, так что вы говорите, я должен сделать 3 отдельных запроса? Один, чтобы получить рецепт, один, чтобы получить шаги, а затем еще один, чтобы получить ингредиенты?

herbie 10.04.2022 10:38

Попробуйте SELECT DISTINCT r.id, rs.id, i.id FROM ... ?

the_nuts 10.04.2022 10:41

Спасибо @the_nuts, к сожалению, это не работает.

herbie 10.04.2022 10:58

@herbie Это правильно, сначала запросите рецепты, затем просмотрите результаты и объявите ингредиенты и шаги.

Grumpy 10.04.2022 11:16
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
1
7
30
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У вас есть декартово произведение

Когда у вас есть 3 recipe_steps и 3 ингредиента, и вы пытаетесь выбрать 1 рецепт, вы получите 9 строк. Это потому, что каждый recipe_step также связан с ингредиентом.

Я создал небольшой DBFIDDLE, чтобы показать это.

Запросы в скрипте (которые предполагают, что в этом примере у вас есть 3 шага на рецепт и 3 ингредиента на рецепт):

-- This will return 3 rows, because the are 3 recipe_steps for recipe=1
SELECT *
FROM recipes r
INNER JOIN recipe_steps rs on rs.recipe_id = r.id
WHERE r.id=1
-- This will return 9 rows, 
--     because the are 3 recipe_steps for recipe=1
--     and 3 ingredients for recipe=1
--     and 3 * 3 = 9
SELECT *
FROM recipes r
INNER JOIN recipe_steps rs on rs.recipe_id = r.id
INNER JOIN ingredients_on_recipes ir on ir.recipe_id = r.id
WHERE r.id=1

Это поведение можно решить, только создав отношение (1-1) между recipe_steps и ингредиентами, а затем добавив это отношение в предложение ON запроса.

Спасибо @Luuk, ценю ответ. Теперь я понимаю, к сожалению, 1-1 там не существует. Поэтому мне придется делать запросы отдельно.

herbie 10.04.2022 11:37

Другие вопросы по теме