PHP/MySQL:多对多/相交表问题

PHP/MySQL:多对多/相交表问题,php,mysql,intersect,Php,Mysql,Intersect,我真的不知道如何表达这个问题,所以让我举一个问题的例子: 假设有一个将项目映射到类别的表。每个项目可以有任意数量的类别,当然每个类别可以容纳任意数量的项目。因此,您有一个如下所示的表: 项目和类别 id项目\u id类别\u id 问题是,我想选择所有具有特定类别id的项目id。例如,选择类别id为1和2的所有项目id:我想查找与类别1和类别2关联的所有项目。很明显,我不能使用AND语句,OR语句将返回任何类别的所有item_id,但不一定同时返回这两个类别 这是我的解决方案,也是我能想到的最好

我真的不知道如何表达这个问题,所以让我举一个问题的例子:

假设有一个将项目映射到类别的表。每个项目可以有任意数量的类别,当然每个类别可以容纳任意数量的项目。因此,您有一个如下所示的表:

项目和类别

id项目\u id类别\u id

问题是,我想选择所有具有特定类别id的项目id。例如,选择类别id为1和2的所有项目id:我想查找与类别1和类别2关联的所有项目。很明显,我不能使用AND语句,OR语句将返回任何类别的所有item_id,但不一定同时返回这两个类别

这是我的解决方案,也是我能想到的最好的办法:选择类别id等于1或2的所有项目id;在PHP中迭代结果,并跟踪有多少项id与类别id关联;然后取消设置结果中没有指定类别数的所有项目ID。以下是我的代码片段:

// 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
显然,如果你有很多不同的类别,你选择和处理的信息比你理论上需要的要多。有什么想法吗

谢谢

编辑:下面是一个表格示例,以及我希望从中获得的信息:

id item_id category_id
1 1 1
2 1 2
3 2 1
4 3 2
比如说,我对获取所有类别为1和2的项目感兴趣。如果我只想要类别为1和2的项目,如何从示例表中获取项目1?如果我像上面的例子那样选择类别1或类别2的所有内容,那么在这种情况下,我必须选择整个表,并手动删除项目id的2和3,因为它们与类别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将替换为我正在搜索的类别数

因此,它会找出有多少类别与每个项目的标准相匹配,因为我只想要所有类别都匹配的项目,所以它只会选择类别数等于我要查找的类别数的项目。这当然是假设没有重复的类别或类似的东西


谢谢你的回复

似乎让您感到不安的是,您被迫进行线性搜索,这当然需要时间,但如果您按排序顺序从数据库中选择元素,那么您就不能在Olg n time中使用二进制搜索吗

我希望这有帮助,如果没有,那么也许我误解了你的问题,我希望你能澄清一点

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

这就是你想要的吗?

这是你应该让数据库去做的事情,而不是让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中的数据是准确的,换句话说,category和item ID分别指向categories和items表中的有效条目。如果您使用的数据库支持外键,那么InnoDB engine for MySQL、Postgres等强制执行外键并不困难

要以您想要的格式获取每个类别中的ID列表,在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;
如果您需要的数据不仅仅是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;

谢谢你的回复。问题是,我不是在结果中寻找一个特定的值——我只是想从我的结果中知道每个项目与多少个类别相关。如果这个数字与我正在搜索的类别数不同,那么我就知道这个项目并不包括所有的类别。如果我理解正确的话,我认为二进制搜索不会真正做到这一点,因为我没有寻找特定的值。顺便说一下,我编辑了我的原始帖子,希望能让它更清楚一点。这基本上实现了我选择foo=1或foo=2的意思。换句话说,它更干净是的,但我必须在PHP中进行相同数量的数组处理,以过滤出foo不在1和2中的结果。当然这是不可能的,因为对于任何给定的行,foo都有一个值,但在我的例子中,我希望有多行具有相同的item\u id和一组category\u id。这正是我希望它做的!然而,当我在测试数据库1000+项上运行它时,它似乎有点慢。我在原始帖子中的最后一个查询也做了同样的事情,但我找到了如何使其更快。感谢您的回复-问题是,这将返回您提供的任何类别中的项目,我对所有类别中的项目都感兴趣。不管怎么说,你的计数问题让我思考和回答 他试图解决这个问题。我只需要计算每个项目匹配的类别数,并确保它与我正在寻找的类别数相等。
SELECT item_id FROM items_categories WHERE category_id = 1 AND item_id IN (SELECT item_id FROM items_categories WHERE category_id = 2)