Как создать временную таблицу из тегов?

0

У меня есть product_table с product_id среди нескольких других полей.

Я создаю a tag_table с 2 полями, tag_id и tag_name.

Теги могут быть похожими на "серебро" или "состояние penn" и т.д.

Я также создаю таблицу product_tag_map с product_id и tag_id, чтобы сопоставить продукт с любым количеством тегов.

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

(Очевидно, что я бы использовал tag_id not tag_name, поэтому продукты с тегами [2,4,5], у которых нет тегов [3,6])

Как создать временную таблицу продуктов и заполнить ее соответствующими продуктами?

Обновление

вот моя таблица product_tag_map:

CREATE TABLE `product_tag_map` (
 `product_tag_map_id` int(11) NOT NULL auto_increment,
 `tag_id` int(11) NOT NULL,
 `product_id` int(11) NOT NULL,
 PRIMARY KEY  (`product_tag_map_id`),
 UNIQUE KEY `tag_id` (`tag_id`,`product_id`),
 KEY `tag_id_2` (`tag_id`)
) ENGINE=MyISAM AUTO_INCREMENT=7897 DEFAULT CHARSET=utf8

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

Теги:

2 ответа

1
Лучший ответ

Вопрос в том, для чего вам нужна временная таблица? Почему бы не запросить его напрямую?

SELECT
  p.product_id,
  p.product_name
FROM
  product_table p
WHERE
  EXISTS (
    SELECT 1 
      FROM product_tag_map 
     WHERE product_id = p.product_id AND tag_id IN (2,4,5)
  )
  AND NOT EXISTS (
    SELECT 1 
      FROM product_tag_map 
     WHERE product_id = p.product_id AND tag_id IN (3,6)
  )

Создайте соответствующие индексы (один индекс с несколькими столбцами над (product_tag_map.product_id, product_tag_map.tag_id) и один отдельный над (product_tag_map.tag_id), в дополнение к "нормальным" индексам PK/FK), и это должно быть довольно быстро.


РЕДАКТИРОВАТЬ: Кэшируемая (по сравнению с планами запросов), и более динамичный вариант выше:

Создайте таблицу user_searches (search_session_id, tag_id, include) с индексом multi_column над (search_session_id, include) и отдельным индексом над tag_id. Затем заполните его, когда пользователь выбирает критерии:

search_session_id   tag_id   include
              ...
             4711        2         1
             4711        4         1
             4711        5         1
             4711        3         0
             4711        6         0
              ...

И запрос вроде этого:

SELECT
  p.product_id,
  p.product_name
FROM
  product_table p
WHERE
  EXISTS (
    SELECT 1 
      FROM product_tag_map m INNER JOIN user_searches s ON s.tag_id = m.tag_id
     WHERE m.product_id = p.product_id 
           AND s.search_session_id = 4711 /* this should be a parameter */
           AND s.include = 1
  )
  AND NOT EXISTS (
    SELECT 1 
      FROM product_tag_map m INNER JOIN user_searches s ON s.tag_id = m.tag_id
     WHERE m.product_id = p.product_id 
           AND s.search_session_id = 4711 /* this should be a parameter */
           AND s.include = 0

  )
  • 0
    +1 Кажется, это отлично работает с моим быстрым прототипом. Я заканчиваю тем, что много манипулирую категориями. Главным образом потому, что я даю пользователю много возможностей сузить категорию, чтобы отфильтровать их результаты. Мне проще сначала поместить категорию в качестве временной таблицы, а затем выполнить пользовательские фильтры для временной таблицы. Это плохая идея?
  • 0
    @John: Поскольку создание временных таблиц вызывает операции записи (и занимает место), я бы сказал, что это плохая идея. Если все, что вы делаете, это манипулируете фильтром, приведенный выше оператор, вероятно, быстрее и экономит ресурсы. Сузить поиск можно даже в самом приложении, без обращений к серверу БД.
Показать ещё 7 комментариев
1

Вы можете создать представление для оператора select.

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

Однако ваш запрос может выглядеть так:

SELECT 
product_id, count(*) as total 
FROM tag_map WHERE tag_id IN (2,4,5) 
AND total = 3 
AND product_id NOT IN (
SELECT product_id, count(*) as total FROM tag_map WHERE tag_id IN (3,6) 
WHERE total = 2 GROUP BY ( product_id )
)
GROUP BY ( product_id )

вы также можете делать соединения, но я думаю, что он будет медленнее.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню