MySQL запрос WHERE NOT EQUAL не работает - PullRequest
0 голосов
/ 23 мая 2018

У меня есть 3 таблицы в моей БД: рецепты, ингредиенты и recipe_ingredients.Рецепты и ингредиенты связаны со многими ко многим, поэтому таблица recipe_ingredients является соединительной таблицей.Я хочу выбрать все рецепты из таблицы рецептов, которая не включает ингредиенты с идентификатором X. И все равно возвращает все рецепты.Если я напишу запрос на возврат рецептов с ингредиентом X, это сработает.Вот мой запрос:

select * from recipes
join recipe_ingredients ON recipes.id = recipe_ingredients.fk_Recipe
join ingredients ON recipe_ingredients.fk_Ingredient = ingredients.id
where recipe_ingredients.fk_Ingredient != 307
GROUP by recipes.url  

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Любой рецепт, который удовлетворяет условию в качестве ингредиента, отличного от 307.

То есть, для этого запроса не имеет значения, является ли один из ингредиентов 307, если в рецепте есть некоторыедругой ингредиент, кроме 307, это совпадение.

Чтобы получить рецепты, в которых ингредиент не имеет 307, мы можем использовать анти-соединение или НЕ СУЩЕСТВУЮЩИЙ


шаблон анти-объединения

 SELECT r.id
      , r.url
   FROM recipes r
   LEFT
   JOIN recipe_ingredients s
     ON s.fk_recipe     = r.id
    AND s.fk_ingredient = 307
  WHERE s.fk_ingredient IS NULL

-или-

шаблон не существует

 SELECT r.id
      , r.url
   FROM recipes r
  WHERE NOT EXISTS 
        ( SELECT 1
            FROM recipe_ingredients s
           WHERE s.fk_recipe     = r.id
             AND s.fk_ingredient = 307
        )

FOLLOWUP

Чтобы вернуть рецепты, которые не имеют 307 в качестве ингредиента, но do имеют 42 в качестве ингредиента ...

 SELECT r.id
      , r.url
   FROM recipes r
   JOIN recipe_ingredients t
     ON t.fk_recipie    = r.id
    AND t.fk_ingredient = 42 
   LEFT
   JOIN recipe_ingredients s
     ON s.fk_recipe     = r.id
    AND s.fk_ingredient = 307
  WHERE s.fk_ingredient IS NULL

-или-

 SELECT r.id
      , r.url
   FROM recipes r
  WHERE NOT EXISTS
        ( SELECT 1
            FROM recipe_ingredients s1
           WHERE s1.fk_recipe     = r.id
             AND s1.fk_ingredient = 307
        )
    AND EXISTS 
        ( SELECT 1
            FROM recipe_ingredients s2
           WHERE s2.fk_recipe     = r.id
             AND s2.fk_ingredient = 42
        )
0 голосов
/ 23 мая 2018

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

Вы можете использовать условие having, например так:

select   recipes.url 
from     recipes
    join recipe_ingredients on recipes.id = recipe_ingredients.fk_Recipe
    join ingredients        on ingredients.id = recipe_ingredients.fk_Ingredient
group by recipes.url 
having   not(sum(recipe_ingredients.fk_Ingredient = 307))

При использовании этого в сочетании с "положительными" условиями, то есть, когда должен использоваться определенный ингредиент , продолжайте использовать тот же шаблон, но на этот раз безnot:

select   recipes.url 
from     recipes
    join recipe_ingredients on recipes.id = recipe_ingredients.fk_Recipe
    join ingredients        on ingredients.id = recipe_ingredients.fk_Ingredient
group by recipes.url 
having   not(sum(recipe_ingredients.fk_Ingredient = 307))
   and   sum(recipe_ingredients.fk_Ingredient = 1105)

Если у вас есть условия для количества ингредиентов, добавьте условие count в предложение having, например:

select   recipes.url 
from     recipes
    join recipe_ingredients on recipes.id = recipe_ingredients.fk_Recipe
    join ingredients        on ingredients.id = recipe_ingredients.fk_Ingredient
group by recipes.url 
having   not(sum(recipe_ingredients.fk_Ingredient = 307))
   and   sum(recipe_ingredients.fk_Ingredient = 1105)
   and   count(*) = 2

Этот метод должен быть очень эффективным: он не требует выполнения подзапроса или объединения в одну и ту же таблицу более одного раза.

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