Подзапросы, фильтрующие слишком много строк - PullRequest
0 голосов
/ 23 февраля 2020

Мои подзапросы отфильтровывают слишком много результатов. Следует отфильтровать 12 ингредиентов, использованных в 3 рецептах в подзапросах. Всего 79 ингредиентов, поэтому запрос должен вернуть 67 строк. В настоящее время мой запрос возвращает 54.

Я не уверен, почему, но если я заменю второе условие WHERE на ИЛИ вместо И, я получу 68 строк, что только на одну единицу от ожидаемого

Запрос, который я пытаюсь создать:

(5) Найдите идентификаторы и названия всех ингредиентов, не используемых в Iri sh Stew, Pollo Picoso или Roast Beef. (2 столбца, 67 строк)

select distinct Recipes.RecipeID, Ingredients.IngredientName
from Recipes
inner join Recipe_Ingredients on Recipes.RecipeID = Recipe_Ingredients.RecipeID
inner join Ingredients on Recipe_Ingredients.IngredientID = Ingredients.IngredientID
where Ingredients.IngredientID NOT IN
    (select distinct Ingredients.IngredientID
    from Recipes
    join Recipe_Ingredients on Recipes.RecipeID = Recipe_Ingredients.RecipeID
    join Ingredients on Recipe_Ingredients.IngredientID = Ingredients.IngredientID
    where Recipes.RecipeTitle = 'Roast Beef')
and Ingredients.IngredientID NOT IN
    (select distinct Ingredients.IngredientID
    from Recipes
    join Recipe_Ingredients on Recipes.RecipeID = Recipe_Ingredients.RecipeID
    join Ingredients on Recipe_Ingredients.IngredientID = Ingredients.IngredientID
    where Recipes.RecipeTitle = 'Irish Stew')
and Ingredients.IngredientID NOT IN
    (select distinct Ingredients.IngredientID
    from Recipes
    join Recipe_Ingredients on Recipes.RecipeID = Recipe_Ingredients.RecipeID
    join Ingredients on Recipe_Ingredients.IngredientID = Ingredients.IngredientID
    where Recipes.RecipeTitle = 'Pollo Picoso');

Диаграмма базы данных: enter image description here

Создание базы данных в формате I Fiddble

Ответы [ 3 ]

1 голос
/ 24 февраля 2020

Этот запрос:

select distinct ri.IngredientID
from Recipe_Ingredients ri inner join Recipes r
on r.RecipeID = ri.RecipeID
where r.RecipeTitle in ('Roast Beef', 'Irish Stew', 'Pollo Picoso')

возвращает 12 ингредиентов, которые вы хотите исключить. Только таблицы Recipe_Ingredients и Recipes должны быть объединены. Теперь оставьте присоединение Ingredients к этому запросу и верните только несопоставленные строки:

select i.IngredientID, i.IngredientName
from Ingredients i
left join (
  select ri.IngredientID
  from Recipe_Ingredients ri inner join Recipes r
  on r.RecipeID = ri.RecipeID
  where r.RecipeTitle in ('Roast Beef', 'Irish Stew', 'Pollo Picoso')
) t on t.IngredientID = i.IngredientID  
where t.IngredientID is null

Вы также можете получить те же результаты с NOT IN:

select IngredientID, IngredientName
from Ingredients 
where IngredientID not in (
  select ri.IngredientID
  from Recipe_Ingredients ri inner join Recipes r
  on r.RecipeID = ri.RecipeID
  where r.RecipeTitle in ('Roast Beef', 'Irish Stew', 'Pollo Picoso')
)

См. демо . Результат - 67 рядов ингредиентов.

1 голос
/ 24 февраля 2020

Я предпочитаю присоединяться только тогда, когда меня интересует объединенный результат. Это не тот случай, здесь. Вы только хотите видеть компоненты, соответствующие некоторому условию. Это FROM ingredients WHERE .... Условия принадлежат предложению WHERE. Таким образом, вы получаете запрос, который легко понять и, следовательно, хорошо обслуживать.

DISTINCT с другой стороны, очень часто является признаком плохо написанного запроса (просто объединение всего, а затем поиск некоторых средств, чтобы избавиться от что мы излишне произвели сами). Это также может быть довольно дорогостоящим, потому что это создает больший промежуточный результат, который затем должен быть отсортирован, чтобы найти созданные дубликаты.

Я бы использовал NOT IN и IN, чтобы получить все ингредиенты, которые не в наборе ингредиентов, рецепт которых в «Жаркое из говядины», «Ири sh Рагу» и «Полло Пикосо».

select ingredientid, ingredientname
from ingredients 
where ingredientid not in 
(
  select ingredientid
  from recipe_ingredients
  where recipeid in
  (
    select recipeid
    from recipes 
    where recipetitle in ('Roast Beef', 'Irish Stew', 'Pollo Picoso')
  )
)
order by ingredientid;
0 голосов
/ 23 февраля 2020

Полагаю, вам нужно только -

select distinct R.RecipeID, I.IngredientName
from Recipes R
inner join Recipe_Ingredients RI on R.RecipeID = RI.RecipeID
inner join Ingredients I on RI.IngredientID = I.IngredientID
where R.RecipeTitle not in ('Roast Beef',  'Irish Stew',  'Pollo Picoso');

Дайте мне знать, если это не соответствует вашим требованиям.

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