Php 如何从标记创建临时表?

Php 如何从标记创建临时表?,php,mysql,sql,Php,Mysql,Sql,我有一个product\u表,其中有一个product\u id 我正在创建一个带有两个字段的tag\u表,tag\u id和tag\u name 标签可以是“银色”或“宾夕法尼亚州立大学”等任何东西 我还创建了一个带有product\u id和tag\u id的product\u-tag\u-map表,以便将产品映射到任意数量的标签 如果我想创建一个包含所有标记为“银”、“项链”、“钻石”的产品的类别。但也不包括任何标记为“初始”、“旅程”的产品 (显然,我会使用tag_id而不是tag_na

我有一个
product\u表
,其中有一个
product\u id

我正在创建一个带有两个字段的
tag\u表
tag\u id
tag\u name

标签可以是“银色”或“宾夕法尼亚州立大学”等任何东西

我还创建了一个带有
product\u id
tag\u id
product\u-tag\u-map
表,以便将产品映射到任意数量的标签

如果我想创建一个包含所有标记为“银”、“项链”、“钻石”的产品的类别。但也不包括任何标记为“初始”、“旅程”的产品

(显然,我会使用tag_id而不是tag_name,因此带有标签[2,4,5]的产品没有标签[3,6])

如何创建临时产品表并用匹配的产品填充它

更新 这是我的产品标签地图表:

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\u tag\u map\u id
进行任何操作。我只是习惯于这样给每个表一个主键。因此,如果我删除它,这很好。

问题是,您需要临时表做什么?为什么不直接查询呢

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)
  )
创建适当的索引(除了“正常”PK/FK索引外,在
(product\u tag\u map.product\u id,product\u tag\u map.tag\u id)上创建一个多列索引
,在
(product\u tag\u map.tag\u id)
上创建一个单独的索引),这应该非常快


编辑:一个可缓存(就查询计划而言)且更具动态性的变量是:

创建一个
user\u search
(search\u session\u id,tag\u id,include)
,在
(search\u session\u id,include)
上有一个多列索引,在
tag\u 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

  )
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 )

可以在select语句上创建视图

(视图基本上是一个虚拟表,您可以轻松查询,但它是使用复杂语句中的数据进行上传的。请阅读手册,它在性能和读/写行为方面并不是那么简单。)

但是,您的查询可能如下所示:

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

  )
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 )

您也可以进行连接,但我认为速度会较慢。

+1这似乎与我的快速原型配合得很好。最后我对分类做了很多操作。主要是因为我给了用户很多选项来缩小分类范围以过滤他们的结果。我发现,首先将类别作为临时表,然后在临时表上执行用户过滤器更容易。这是个坏主意吗?@John:因为创建临时表会调用写操作(并消耗空间),所以我认为这是个坏主意。如果您所做的只是操作过滤器,那么上面的语句可能会更快并节省资源。缩小搜索范围甚至可以在应用程序本身中完成,而无需往返数据库服务器。我尝试像您所说的那样编制索引,我有一个唯一的
(product\u tag\u map.product\u id,product\u tag\u map.tag\u id)
,然后当我向
(product\u tag\u map.tag\u id)
添加索引时。它允许我这样做,但我从phpmyadmin得到了这样的警告:
UNIQUE和INDEX键不应该同时为列tag\u id设置
@John Isaacks:您想要的是
(product\u id,tag\u id)
上的聚集索引(主键),而不是唯一键。这用于使用
产品标识
-
标签标识
组合进行查找,以及仅用于
产品标识
-查找。对于
tag\u id
-查找,您需要该列上的另一个(标准)索引。谢谢,我不太确定如何执行此操作,我更新了我的问题以包括我的创建表。您能告诉我如何修改它以获得正确的索引吗?