Выборка вида многие к многим

donflash

Вареник клуба
Выборка вида многие к многим

Есть таблица A, вида (id int, title varchar)
1 апельсин
2 яблоко
3 мандарин
4 ананас
5 вода
6 соль

Есть таблица B, вида (id int, title varchar)
1 сок
2 фруктовый салат
3 суп

Есть таблица соответствий, вида (id int, A_id int, B_id int)
1 1 1
2 1 2
3 5 1
4 5 2
5 5 3
6 2 1

В запрос передаются id, соотв. таблице A, например, передаём массив A = array(1,5);

И показываются все блюда из таблицы B, где есть ингредиенты из таблицы A

Попробую ещё раз разжевать:

Передаём запросу id хлеба и сыра и запрос выводит все блюда, которые содержат именно эти ингредиенты, не больше, ни меньше.

Вечерний ступор налетел, вроде пустяковая задача, а решить не могу( Наведите на мысль плиз...
 

berkut

Новичок
показываются все блюда из таблицы B, где есть ингредиенты из таблицы A
Передаём запросу id хлеба и сыра и запрос выводит все блюда, которые содержат именно эти ингредиенты, не больше, ни меньше.
так _только_ эти ингридиенты и больше никакие, или "в том числе" и указанные ингридиенты?
 

Farsh

~ on ~ high ~ wave ~
А в чем проблема ? Делаешь выборку из таблицы соответствий, где A_id = запрошенному ID и join B_id к таблице B ?
request_id - запрошенный ID ингредиента .
SELECT a_to_b.* , B.* FROM a_to_b, B WHERE a_to_b.A_id = request_id AND a_to_b.B_id = B.id , как то тагг ..

-~{}~ 23.10.08 00:55:

А, видимо нужно выбирать блюда, в которые входят 2+ ингредиентов сразу ?

-~{}~ 23.10.08 01:28:

А вообще если так, то мне самому интересно, чет не додумаюсь ;)
 

Bitterman

Новичок
Насколько я понял, надо выбрать все блюда, которые можно приготовить из этих продуктов, не используя другие. Тогда как-то так: в подзапросе выбрать все блюда, в которые входит хоть один НЕ из этих ингредиентов, а в основном запросе выбрать все другие блюда.
ЗЫ. Поле id в таблице соответствий лишнее.
ЗЫ2. Хотя может быть будет правильней разбить на 2 запроса.
 

HraKK

Мудак
Команда форума
Просидел 2 часа - ответсвтвенно заявляю без подзапроса никак
 

dadoc

Новичок
PHP:
SELECT B.* 
FROM B, A_B 
WHERE B.id = A_B.B_id
GROUP BY B.id HAVING SUM(IF(A_B.A_id IN (1,5),1,0)) = 2 [ AND COUNT(A_B.A_id) = 2)]
COUNT если надо _только_ эти два ингридиента
 

donflash

Вареник клуба
так _только_ эти ингридиенты и больше никакие, или "в том числе" и указанные ингридиенты?
Да, только эти и больше никакие.

А, видимо нужно выбирать блюда, в которые входят 2+ ингредиентов сразу ?
Нет

Насколько я понял, надо выбрать все блюда, которые можно приготовить из этих продуктов, не используя другие.
Абсолютно верно

dadoc , спасибо, сейчас попробую...

-~{}~ 23.10.08 12:27:

SUM(IF(A_B.A_id IN (1,5),1,0)) = 2
А к чему эта проверка? Ингредиентов может быть и 3 и 4 и 34
 

Bitterman

Новичок
А к чему эта проверка? Ингредиентов может быть и 3 и 4 и 34
Ну число элементов можно вычислить перед запросом и просто подставить туда. Другое дело, что, насколько я понимаю, этот запрос выведет блюда которые состоят обязательно из всех выбранных элементов.
Возможно, будет работать если условие заменить на
[sql]
HAVING SUM(IF(A_B.A_id IN (1,5),1,0)) = COUNT(A_B.A_id)
[/sql]
то есть общее число ингредиентов должно совпадать с числом ингредиентов входящих в выбранный набор. Не проверял, ессно.
 

dadoc

Новичок
Автор оригинала: donflash


А к чему эта проверка? Ингредиентов может быть и 3 и 4 и 34
Хмм, если один и тот же ингридиент в Вашем примере может быть использован несколько раз для приготовления, тогда надо напиать
PHP:
SUM(IF(A_B.A_id = 1, 1, 0)) > 0 AND SUM(IF(A_B.A_id = 5, 1, 0)) > 0 AND SUM(IF(A_B.A_id NOT IN (1,5), 1, 0)) = 0
Но я думаю вместо несольких запичей в таблице A_B лушче добавить новое поле "колличество" и сделать (A_id,B_id) первичным ключом
 

donflash

Вареник клуба
Большое спасибо всем за помощь, действительно, задача решается довольно просто.

В общем, вот два эквивалентных запроса:

[sql]
/*#1*/

SELECT
A.title
,A.icount
FROM
A
LEFT JOIN A_B ON A_B.A_id = A.id
GROUP BY
A.id
HAVING
SUM(
IF(A_B.B_id IN (1,2,4,3),1,0)
) = A.icount
[/sql]

[sql]
/*#2*/
SELECT
A.*
FROM
A, A_B
WHERE
A.id = A_B.A_id
GROUP BY
A.id
HAVING
SUM(
IF(A_B.B_id IN (1,2,4,3),1,0)
) = A.icount
[/sql]

Всегда на практие использовал LEFT JOIN, думаете будет ощутимый выигрыш при объёме базы в несколько тысяч записей, если использовать вариант без LEFT JOIN?
 

Bitterman

Новичок
Всегда на практие использовал LEFT JOIN, думаете будет ощутимый выигрыш при объёме базы в несколько тысяч записей, если использовать вариант без LEFT JOIN?
Проверь, это несложно
 
Сверху