2014-01-28 2 views
1

В диалоге «многие ко многим» MySql DB мне нужно выбрать все ресурсы (документы с названиями), которые относятся к категориям в списке (категории с идентификатором 9,10 в приведенном ниже примере).Выделить все связанные значения в отношениях «многие-ко-многим»

Вот модель:

enter image description here

Однако, и это главное: для каждого ресурса, я хочу также получить все категории, ресурс, связанные с ним - не только которые запрашиваются для ... Итак, если ресурс с заголовком: title_1, например, соответствует категориям с идентификаторами 9 и 10, но если этот ресурс действительно также имеет категории 11 и 12, я бы хотел получить эту информацию.

Итак, для запроса, запрашивающего ресурс, где категория соответствует 9 или 10, мне нужен этот ресурс и все его связанные категории. Т.е. информации мне нужно для такого ресурса: название

ресурса: title_1 категория: 9,10,11,12

Даже если я только уточнил, что это необходимо, чтобы соответствовать 9 и 10 в запросе ...

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

То, что я до сих пор это:

SELECT 
    r.title, 
     cr.category_id 
FROM 
    category_resource cr 
      INNER JOIN resource r 
      ON cr.resource_id = r.id 
WHERE cr.category_id IN (9,10) 

Это дает мне строки с ресурсами, помеченных с любым из них, очень быстро (около 10 мс) из БД 5000 строк. В результате 3 названия:

title_1, категория: 9 title_1, категория 10 title_2, категория: 10

Т.е., я получаю два результата для TITLE_1, потому что она имеет как категории 9 и 10. Но я получаю только эти две категории, потому что они были в запросе. Но это не дает мне другие категории, связанные с ресурсом title_1.

Обратите внимание, что я задал аналогичный вопрос раньше, но не совсем. Я получил ответ на этот вопрос, который разрешил его. Но он стал слишком сложным, и мне нужно было перефразировать его, а также дать ему другой подход. Дело здесь: мне нужно получить эту информацию, но она также должна быть почти такой же быстрой, как и текущий более простой запрос, например, около 10 мс. Это может потребовать многого, но в то же время требование не кажется слишком надуманным для меня для базы данных? Т.е. получить элемент, соответствующий критерию, и получить все значения, связанные с ним из таблицы взаимосвязей «многие ко многим» ...

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

ответ

1

Вы можете сделать это с Self-Join:

Вот рабочий sqlfiddle: http://sqlfiddle.com/#!2/1826f/6

Вы уже присоединились на category_resource, чтобы ограничить (9,10), поэтому мы присоединяемся на его копии и получить все результаты, которые соответствуют:

SELECT 
    r.title, 
     cr2.category_id 
FROM 
    category_resource cr 
INNER JOIN resource r 
ON cr.resource_id = r.id 
INNER JOIN category_resource cr2 on cr2.resource_id = r.id 
WHERE cr.category_id IN (9,10) 
GROUP BY cr2.category_id,r.title 
ORDER BY r.title 

Редактировать на основе комментариев: Если вы требуете, чтобы все категорий (9,10), вы можете изменить его самостоятельно присоединиться к РАЗ, как Cr3:

SELECT 
r.title, 
cr2.category_id 
FROM 
category_resource cr 
INNER JOIN resource r 
ON cr.resource_id = r.id 
INNER JOIN category_resource cr2 on cr2.resource_id = r.id 
INNER JOIN category_resource cr3 on cr3.resource_id = r.id 
WHERE cr.category_id = 9 
and cr3.category_id = 10 
GROUP BY cr2.category_id,r.title 
ORDER BY r.title 

sqlfiddle: http://sqlfiddle.com/#!2/1826f/11

ИЛИ здесь версия с использованием HAVING: http://sqlfiddle.com/#!2/1826f/12

SELECT 
r.title, 
cr2.category_id 
FROM 
category_resource cr 
INNER JOIN resource r 
ON cr.resource_id = r.id 
INNER JOIN category_resource cr2 on cr2.resource_id = r.id 
WHERE cr.category_id IN (9,10) 
GROUP BY cr2.category_id,r.title 
HAVING count(cr.category_id)=2 
ORDER BY r.title 
+0

Спасибо, вам нужно немного протестировать его, но, похоже, он работает очень хорошо! Не могли бы вы добавить, как изменить это, чтобы требовать, чтобы cr. category_id также должна соответствовать ALL в списке (9,10)? Это еще один вариант, который мне нужен ... Я знаю, что это обычно делается путем добавления чего-то вроде HAVING COUNT (DISTINCT cr.category_id) = 2 (для списка из двух значений), но я попытался, и я не могу совместить это с чтобы получить действительное заявление ... – Anders

+0

Отлично работает, большое спасибо! – Anders

0

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

0

Итак,

SELECT 
     r.title, 
     cr.category_id 
FROM 
    category_resource cr 
      INNER JOIN resource r 
      ON cr.resource_id = r.id 
WHERE cr.category_id IN (9,10) 

дает вам все ресурсы, которые имеют идентификатор категории из 9 или 10.

Если изменить это немного

SELECT DISTINCT 
      r.title, 
      cr2.category_id 
    FROM 
     category_resource cr 
    INNER JOIN resource r 
       ON cr.resource_id = r.id 
    INNER JOIN category_resource cr2 
       ON cr.resource_id = cr2.resource_id 
    WHERE cr.category_id IN (9,10) 

Вы должны быть в состоянии захватить другие категории ресурсов, кроме 9 и 10.

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

Измените запрос, который показывает все ресурсы с категориями 9 или 10. Добавьте еще одно внутреннее соединение к таблице, содержащее каждую пару паттерна/категории (здесь я не уверен, что следую вашей схеме). Присоединяйтесь к названию. Получите дополнительные категории из таблицы, содержащей пару title/category.

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

Смежные вопросы