2011-02-02 3 views
2

Я не совсем уверен, как фраза вопрос, поэтому позвольте мне привести пример проблемы:PHP/MySQL: Многие ко многим/пересекаться таблица вопрос

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

items_categories

ID item_id CATEGORY_ID

Проблема заключается в том, я хочу, чтобы выбрать все запись идентификаторов, которые имеют определенную категорию идентификаторов. Например, выберите все item_id с category_id из 1 и 2: я хочу найти все элементы, связанные с категориями как 1, так и 2. Очевидно, я не могу использовать инструкцию AND, и оператор OR вернул бы все item_id с любой категорией , но не обязательно оба.

Вот мое решение и лучшее, что я могу придумать: выберите все item_ids с category_id равным 1 ИЛИ 2; перебирать результаты в PHP и отслеживать, сколько item_id связано с category_id; а затем отключить все item_ids в результатах, которые не имеют указанного количества категорий. Вот отрывок из моего кода:

// assume $results is an array of rows from the db 
// query: SELECT * FROM items_categories WHERE category_id = 1 OR category_id = 2; 
$out = array(); 
foreach ($results as $result) 
{ 
    if (isset($out[$result['item_id']])) 
     $out[$result['item_id']] ++; 
    else 
     $out[$result['item_id']] = 1; 
} 
foreach ($out as $key=>$value) 
{ 
    if ($value != 2) 
     unset($out($key)); 
} 
return array_keys($out); // returns array of item_ids 

Очевидно, что если у вас есть много различных категорий, вы выбираете и обработки намного больше информации, чем вы должны теоретически нужно. Есть идеи?

Спасибо!

Edit: Вот пример таблицы и информации, которую я хочу от него:

id item_id category_id 
1 1 1 
2 1 2 
3 2 1 
4 3 2 

Так сказать, я заинтересован в том, чтобы все элементы с категориями 1 и 2. Как получить элемент № 1 из моей таблицы примеров, учитывая, что я хочу только предметы с категориями # 1 и # 2? Если я выбираю все с категориями 1 или 2 (как в моем примере выше), я должен выбрать всю таблицу в этом случае и «вручную» удалить 2 и 3 item_id, так как они не связаны как с категориями 1, так и с категория 2. Надеюсь, это поможет немного разъяснить.

Окончательное изменение: Я понял это, несмотря на мою явную неспособность описать то, что я пытаюсь сделать, хе. Вот запрос я придумал, для записи:

SELECT * 
FROM 
(
    SELECT item_id, COUNT(*) as count 
     FROM items_categories 
     WHERE category_id IN (1, 2) 
    GROUP BY item_id 
) table_count 
WHERE count = 2; 

В этом случае "(1, 2)" можно заменить "( category_id1, category_id2, ...)" , а «2» в конце будет заменено числом категорий, которые я ищу.

Таким образом, выясняется, сколько категорий соответствует критериям для каждого элемента, и поскольку мне нужны только те предметы, где ВСЕ категории соответствуют, они выбирают только те, где число категорий равно числу категорий, которые я ищу. Это, конечно, предполагает, что нет повторяющихся категорий или чего-либо подобного.

Спасибо за ответы!

ответ

1

Похоже, что вас беспокоит то, что вы вынуждены выполнять линейный поиск, который, конечно, занимает время O (n), но если вы выберете элементы из вашей базы данных в отсортированном порядке, то вы не можете просто использовать бинарный поиск в O (lg n) времени?

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

+0

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

+0

Кстати, я отредактировал свое оригинальное сообщение, надеюсь, сделаю это немного более понятным. – user599599

0
SELECT 
foo 
FROM 
bar 
WHERE 
foo IN (1,2) 

Это то, что вы ищете?

+0

Это в основном выполняет то, что я имею в виду, выбрав foo = 1 OR foo = 2. Другими словами, это чище да, но мне нужно было бы сделать то же самое количество обработки массивов в PHP, чтобы отфильтровывать результаты, где «foo» isn 't как в 1 И 2. (Конечно, это невозможно, так как для любой заданной строки «foo» имеет одно значение, но в моем случае я ожидаю несколько строк с одним и тем же item_id и набором category_id.) – user599599

0

Это то, что вам нужно делать, чтобы база данных выполнялась, а не PHP.

SELECT item_id     # We want a list of item ids 
FROM cat_items     # Gets the item ID list from the cat_items table 
WHERE cat_id IN (1, 2, 7, 11) # List of categories you want to search in 
GROUP BY item_id;    # As the same item can appear in more than one category this line will eliminate duplicates 

Этот запрос делает предположить, что данные в cat_items является точной, другими словами, что идентификаторы категории и пункт указывают на допустимые записи в категории и предметы таблиц соответственно. Если вы используете базу данных с поддержкой внешнего ключа (механизм InnoDB для MySQL, Postgres и т. Д.), Обеспечивающий использование внешних ключей, это не сложно.

Чтобы получить список идентификаторов в каждой категории в нужном вам формате, это легко сделать и на стороне SQL.

SELECT * 
FROM cat_items 
WHERE cat_id IN (1, 2, 7, 11) 
GROUP BY cat_id, item_id; 

Если вы просто хотите подсчет того, сколько элементов в каждой категории вы можете также сделать это в SQL

SELECT cat_id, COUNT(item_id) AS items 
FROM cat_items 
WHERE cat_id IN (1, 2, 7, 11) 
GROUP BY cat_id; 

Если вам нужно больше информации, чем просто идентификатор, то вы можете присоединиться против вам нужны данные.

SELECT items.* 
FROM cat_items 
JOIN items ON cat_items.item_id = items.id 
WHERE cat_id IN (1, 2, 7, 11) 
GROUP BY item_id; 
+0

Спасибо за ответ - вещь есть, что вернет элементы, которые находятся в * любом * из категорий, которые вы ему даете, и меня интересуют элементы, которые находятся во всех * категориях. В любом случае, ваш запрос подсчета заставил меня задуматься и привел к решению проблемы. Мне просто нужно было подсчитать количество категорий, которые соответствуют каждому элементу, и убедиться, что это равно количеству категорий, которые я ищу. – user599599

0
SELECT item_id FROM items_categories WHERE category_id = 1 AND item_id IN (SELECT item_id FROM items_categories WHERE category_id = 2) 
+0

Это именно то, что я хочу! Однако, когда я запускал его против своей тестовой базы данных (1000+ элементов), это выглядело немного медленнее. Мой последний запрос в исходном сообщении делает то же самое, но я понял, как сделать это быстрее. – user599599

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

  • Нет связанных вопросов^_^