2011-02-02 46 views
2

我真的不知道如何短语的问题,所以让我给这个问题的一个例子:PHP/MySQL的:许多一对多/交叉表问题

假设有它映射项的表格分类。每个项目可以有任意数量的类别,每个类别当然可以包含任意数量的项目。所以,你有一个表,如下所示:

items_categories

ID ITEM_ID CATEGORY_ID

的问题是,我想选择所有项目的ID具有特定类别的ID。例如,选择category_id's为1和2的所有item_id's:我想查找与类别1和2相关联的所有项目。显然,我不能使用AND语句,并且OR语句将返回所有item_id与任一类别,但不一定都是。

这里是我的解决方案和我能想到的最好的东西:选择category_id等于1或2的所有item_id;迭代PHP中的结果并跟踪有多少item_ids与category_id关联;然后取消设置没有指定数量类别的结果中的所有item_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 

显然,如果你有很多不同的类别,你选择和处理方式应该比你理论上需要更多的信息。有任何想法吗?

谢谢!

编辑:这里有一个表和信息的一个例子,我想从它:

​​

所以说,我感兴趣的是让所有的物品与第1类和2我如何因为我只想要类别为#1 #2的物品,所以从我的示例表中获取物品#1?如果我选择类别1 2(如上例所示),我必须在这种情况下选择整个表格,并“手动”删除item_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”将被我正在搜索的类别数量所取代。

因此,它会找出有多少类别符合每件商品的标准,并且由于我只希望所有商品类别都匹配的商品,因此只会选择类别数量等于我要查找的商品类别数量的商品。这当然假设没有重复的类别或类似的东西。

感谢您的回复!

回答

1

看来,什么是困扰你的是,你不得不做,当然这需要O(n)的时间线性搜索,但如果你选择的排序顺序从数据库元素,那么你就不能使用O(lg n)时间的二进制搜索?

我希望这可以帮助,如果没有,那么也许我误解你的问题,我想请你澄清这一点。

+0

感谢您的回复。事情是,我没有在结果中寻找具体的价值 - 我只是想从我的结果中知道每个项目有多少种类与之相关联。如果该数字与我正在搜索的类别数量不同,那么我会知道该项目不包含所有类别。如果我正确理解这一点,我认为二进制搜索不会真的实现这一点,因为我没有寻找具体的价值。 – user599599 2011-02-02 08:10:34

+0

顺便说一句,我编辑了我原来的帖子,希望能够让它更清楚一点。 – user599599 2011-02-02 08:17:36

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

这是你在找什么?

+0

,基本上实现了通过选择其中foo = 1或富= 2。换句话说,它的清洁是我的意思,但我必须做在PHP数组处理同样数量的过滤出结果,其中“富” ISN (当然,这是不可能的,因为对于任何给定的行,“foo”有一个值,但在我的情况下,我期望多行具有相同的item_id和一组category_id)。 – user599599 2011-02-02 08:14:50

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的数据是准确的,在该类别和项目ID指向分别在类别和项目表中的有效条目等字样。如果你使用的是支持外键的数据库(MySQL的InnoDB引擎,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; 
+0

感谢您的答复 - 事情是,这将返回在*你给它的类别中的任何*的项目,我感兴趣的是在* *所有类别的项目。无论如何,你的计数查询让我思考并导致解决问题。我只需要计算每个项目匹配的类别数量,并确保这与我正在查找的类别数量相等。 – user599599 2011-02-02 20:26:37

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)