Подсчет различных записей с использованием нескольких критериев из другой таблицы в MySQL - PullRequest
4 голосов
/ 19 ноября 2010

Это не домашняя работа. Я изменил названия таблиц и полей, только для иллюстративных целей. Я признаю, что я совершенно новичок в MySQL. Пожалуйста, учтите это в своем ответе.

Лучший способ проиллюстрировать функцию запроса, который мне нужен, выглядит следующим образом:

У меня есть две таблицы.

Одна таблица имеет отношение от 0,1 до 0..n к другой таблице.

Только для простоты. Предположим, что двумя таблицами были Рецепт и Ингредиент.

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

Только для примера: alt text

Я хочу знать SQL для чего-то вроде: Сколько рецептов требует "Оливки" в количестве "1" И "Грибы" в количестве "2"

Будучи новичком в языке структурированных запросов, я даже не знаю, что искать в Google для этой информации.

Я на правильном пути со следующим?:

SELECT COUNT(DISTINCT Recipe.ID) AS Answer FROM Recipe, Ingredient 
  WHERE Ingredient.RecipeID=Recipe.ID AND Ingredient.Name='Olives'
  AND Ingredient.Amount=1 AND Ingredient.Name='Mushrooms'
  AND Ingredient.Amount=2

Я понимаю, что это совершенно неправильно, потому что Имя не может быть ОБА Оливками и грибами ... но я не знаю, что вместо этого положить, так как мне нужно сосчитать все рецепты с обоими, но только все рецепты с обоими.

Как правильно написать такой запрос для MySQL?

Ответы [ 5 ]

3 голосов
/ 19 ноября 2010

Использование:

SELECT COUNT(r.id)
  FROM RECIPE r
 WHERE EXISTS(SELECT NULL
                FROM INGREDIENTS i
               WHERE i.recipeid = r.id
                 AND i.name = 'Olives'
                 AND i.amount = 1)
   AND EXISTS(SELECT NULL
                FROM INGREDIENTS i
               WHERE i.recipeid = r.id
                 AND i.name = 'Mushrooms'
                 AND i.amount = 2)
3 голосов
/ 19 ноября 2010

Вы были близки.

Попробуйте что-то вроде

SELECT  COUNT(Recipe.ID) Answer
FROM    Recipe INNER JOIN
        Ingredient olives ON olives.RecipeID=Recipe.ID INNER JOIN
        Ingredient mushrooms ON mushrooms.RecipeID=Recipe.ID 
WHERE   olives.Name='Olives'
AND     mushrooms.Name='Mushrooms'
AND     olives.Amount = 1
AND     mushrooms.Amount = 2

Вы можете присоединиться к одной и той же таблице дважды, все, что вам нужно сделать, это дать таблице соответствующий псевдоним .

1 голос
/ 19 ноября 2010
SELECT COUNT(DISTINCT Recipe.ID) AS Answer 
FROM Recipe, Ingredient as ing1, Ingredient as ing2
WHERE 
  Ing1.RecipeID=Recipe.ID AND Ing1.Name="Olives" AND ing1.Amount=1 AND 
  Ing2.RecipeID=Recipe.ID AND Ing2.Name="Mushrooms" AND ing2.Amount=2;

Надеюсь, что эта помощь

0 голосов
/ 19 ноября 2010

Только для справки ...

Сколько рецептов называют «Оливки» на сумму «1» И «Грибы» на сумму «2»

Рассматривая структуру таблицы выше, вы можете захотеть, чтобы ассоциативная сущность шла между рецептами и ингредиентами. Это значительно упрощает выполнение запросов, которые вы ищете с помощью внутреннего соединения .

Между вашими двумя столами я мог бы представить что-то вроде этого ...

Recipe_Ingredient
-----------------
(PK, FK) RecipeID
(PK, FK) IngredientID

Если у вас это есть, то в каждом рецепте может быть много ингредиентов, и каждый ингредиент может быть частью многих рецептов. Если у вас есть такая таблица, чтобы правильно связать две таблицы, вы можете объединить их и получить полный рецепт. Для более сложного запроса, такого как этот, когда у вас есть отдельные условия для двух рецептов, я бы, вероятно, подзапросил его, чтобы помочь пониманию.

SELECT SUM(RecipeCount) as RecipeCount
FROM
(
    SELECT COUNT(r.*) as RecipeCount
    FROM Recipe r
    INNER JOIN Recipe_Ingredient ri on r.ID = ri.RecipeID
    INNER JOIN Ingredient i on i.ID = ri.IngredientID
    WHERE i.Name = 'Olives' AND i.Amount = 1
UNION ALL
    SELECT COUNT(r.*) as RecipeCount
    FROM Recipe r
    INNER JOIN Recipe_Ingredient ri on r.ID = ri.RecipeID
    INNER JOIN Ingredient i on i.ID = ri.IngredientID
    WHERE i.Name = 'Mushrooms' AND i.Amount = 2
) as subTable
0 голосов
/ 19 ноября 2010

Прежде всего, вы используете старый синтаксис соединения. INNER JOIN создает тот же план выполнения, но гораздо более понятный. Тогда ваш запрос все о простом, старом состоянии. Вы просто должны написать их правильно! (Согласен, нужно немного практики.)

SELECT COUNT(DISTINCT R.ID) Answer
FROM Recipe R
INNER JOIN Ingredient I
    ON R.ID = I.RecipeID
    AND (R.Name = 'Olives' AND I.Amount = 1)
    OR (R.Name = 'Mushrooms' AND I.Amount = 2);

Вот мои примерные данные:

mysql> SELECT * FROM Ingredient;
+------+------+--------+----------+
| ID   | Name | Amount | RecipeID |
+------+------+--------+----------+
|    1 | I1   |      1 |        1 |
|    1 | I2   |      2 |        1 |
|    1 | I3   |      2 |        1 |
|    1 | I4   |      3 |        1 |
|    1 | I1   |      1 |        2 |
|    1 | I2   |      1 |        2 |
|    1 | I3   |      3 |        2 |
|    1 | I4   |      2 |        2 |
|    1 | I1   |      2 |        3 |
|    1 | I2   |      1 |        3 |
+------+------+--------+----------+
10 rows in set (0.00 sec)

mysql> SELECT * FROM Recipe;
+------+-----------+
| ID   | Name      |
+------+-----------+
|    1 | Mushrooms |
|    2 | Olives    |
|    3 | Tomatoes  |
+------+-----------+
3 rows in set (0.00 sec)

И мой запрос выводит 2, как и должно быть.

Редактировать: На самом деле я понял, что мой запрос выбрал неправильные строки. Это работает правильно:

SELECT COUNT(DISTINCT R.Id) Answer 
FROM Recipe R 
INNER JOIN Ingredient I 
    ON R.ID = I.RecipeID 
WHERE 
    (R.Name = 'Mushrooms' AND I.Amount = 2) 
    OR (R.Name = 'Olives' AND I.Amount = 1);

Который также выводит 2.

...