Php 查找mysql表中出现的标记项

Php 查找mysql表中出现的标记项,php,mysql,Php,Mysql,假设我有这张桌子: item_id tag_id ------- ------ 1 1 1 2 2 2 2 3 正如您可能想象的那样,这是一个表,我在其中引用了一些属于它们的项和标记。一个项目可以有多个标记,并且可以为多个项目选择一个标记 假设我还有一个特殊的标签collecion f.ex。tag_id=50、73和119,以及具有由item_id引用的id的items表 是否有一个有效的查询可以为我提供: 具有这些标记的项目的计数 项目本身?

假设我有这张桌子:

item_id tag_id
------- ------
1       1
1       2
2       2
2       3
正如您可能想象的那样,这是一个表,我在其中引用了一些属于它们的项和标记。一个项目可以有多个标记,并且可以为多个项目选择一个标记

假设我还有一个特殊的标签collecion f.ex。tag_id=50、73和119,以及具有由item_id引用的id的items表

是否有一个有效的查询可以为我提供:

具有这些标记的项目的计数 项目本身? 我试过的

我可以同时得到这两个结果,但是使用一个非常低效的查询。经过一次解释性的检查后,我想去掉ORs给出的范围

完善我的问题:问题是我得到了一个编写得非常糟糕的PHP框架,它通过各种标记ID迭代了900多次。假设您有一个或多个选定标记的固定ID,它遍历所有900+标记,以查找具有给定标记加上迭代标记的共同项的出现次数。这是一个优化搜索的函数,仅显示具有所有给定标记加上一的元素

给定的代码是这样工作的:我选择一个或多个标记,它们的ID进入querystring。假设我选择了标记54和77。 代码必须找到同时具有标记54和77的项目的每个项目ID,并逐一列出它们:我们获得具有所选标记的项目列表

然后,它提供了优化搜索的选择,接下来是奇怪的部分:PHP代码循环遍历所有900多个标记,每次迭代都会使用一个标记,并统计有多少项包含所有标记54、77和迭代中的一个。 如果计数>0,它将显示带有计数编号的标记名称,过滤掉其项目与所选标记没有任何链接的每个标记


最好以不太密集的方式获得相同的结果。

要获得与所有标记匹配的项目ID列表,可以使用以下查询:

SELECT items.id
FROM items
JOIN items_tags ON items.id = items_tags.item_id
WHERE (items_tags.tag_id IN (7,95,150))
  AND (items.status = 'active')
GROUP BY items.id
HAVING COUNT(DISTINCT items_tags.tag_id) = 3
请注意,如果您确定同一项目没有重复的标记,可以使用COUNT*替换COUNTDISTINCT items\u tags.tag\u id以提高效率

要获取这些项目的计数,请将其包装到计数查询中:

SELECT COUNT(*)
FROM (
  SELECT items.id
  ...
) t
要获取项目列表,请将其包装在此选择查询中:

SELECT *
FROM items
WHERE id IN (
  SELECT items.id ...
)
更新

要在与原始列表组合时获取每个剩余标记的项目计数,可以执行以下操作:

SELECT tag_id, COUNT(DISTINCT item_id)
FROM items_tags
WHERE item_id IN (
  SELECT items.id
  ...
)
  AND tag_id NOT IN (7,95,150)
GROUP BY tag_id

您希望得到什么样的输出?您想要与所有这些标签或其中任何一个匹配的项目?所有这些,谢谢。在第一种情况下,我期望的输出是匹配所有标记的单个项目数,在第二个问题中,id与包含所有标记的项目id匹配的项目表行。然后,我修改的答案应该可以帮助您。就你的目的而言,它足够有效吗?@PinnyM:不确定。不过,这在某些方面与我所做的类似,这是一个很好的关于拥有子句的提示。我怀疑有一种更有效的方法不使用。。。或者一堆or,似乎查询效率的真正瓶颈是如果它位于表的id列上,是否有明显的必要性?当然,这是假设id是表的主键。@AaronHathaway:我修改了我的答案,以反映OP似乎想要匹配所有标记的项。要回答您的问题,是的,您将需要DISTINCT,否则将返回多行—与项目关联的每个标记对应一行。
SELECT tag_id, COUNT(DISTINCT item_id)
FROM items_tags
WHERE item_id IN (
  SELECT items.id
  ...
)
  AND tag_id NOT IN (7,95,150)
GROUP BY tag_id