多个组的SQL查询将每个组组合为AND语句,并将每个组组合为OR语句

时间:2012-08-27 22:20:13

标签: mysql

我有一个复杂的导航,可以对内容库进行排序。导航对应于类别,图库需要根据导航中选择的类别显示不同的内容组合。导航的结构如下:

GROUP 1
category 1
category 2
category 3

GROUP 2
category 4
category 5
category 6

GROUP 3
category 7
category 8
category 9

我需要编写一个MySQL查询,将每个组中的所有项目视为OR语句。因此,选择1类和2类,应该返回所有标记为1类和2类的项目。

并且,每个组之间的项目需要被视为AND语句。因此,选择第1类和第4类只会返回第1类和第4类中包含的项目。

我可以用简单的形式完成这两个查询,但是当我需要在每个组中包含多个类别的多个组时,我似乎无法将其拉下来。

在英语中,最终查询需要能够做到这样的事情:

"category 1" OR "category 2" OR "category 3" 
AND
"category 4" OR "category 5"
AND
"category 6" OR "category 7"

我为此遇到了很多版本的许多查询,而且我目前还没有一个合适的答案。作为参考,如果值得的话,这就是我现在所拥有的:

SELECT ct.entry_id,
    ct.entry_date AS date,
    ct.title AS title,
    cp.cat_id AS category_id
FROM exp_channel_titles AS ct
LEFT JOIN exp_channel_data AS cd ON ct.entry_id = cd.entry_id
LEFT JOIN exp_category_posts AS cp ON ct.entry_id = cp.entry_id
WHERE ct.channel_id = '2'                        
AND ct.site_id = '1'

AND cp.cat_id IN (119)
AND cp.cat_id IN (121)

GROUP BY ct.entry_id 
ORDER BY ct.entry_date DESC

原因中的cat_id行似乎需要整理出来。我也试过使用HAVING,我从广义上开始工作,但我并不是真的理解它,所以当我尝试修改它以获得更具体的用途时(如果它甚至是正确使用的话)我'没有得到任何有用的结果。以下查询中的变量是根据检查的类别动态构建的:

AND ct.entry_id IN (SELECT entry_id
                FROM exp_category_posts 
                WHERE cat_id IN (".$category_ids.") 
                GROUP BY entry_id
                HAVING COUNT(DISTINCT cat_id) = " . 
                count($category_array) . ")

任何指导都将不胜感激。

更新:感谢戈登的回答,我现在有了一个有效的查询。虽然查询的某些部分是动态构造的(例如选择了哪些类别ID),但这里是查询的静态版本以供参考:

SELECT ct.entry_id,
   ct.entry_date AS date,
   ct.title AS title,
   cp.cat_id AS category_id
FROM exp_channel_titles AS ct
LEFT JOIN exp_channel_data AS cd ON ct.entry_id = cd.entry_id
LEFT JOIN exp_category_posts AS cp ON ct.entry_id = cp.entry_id
WHERE ct.channel_id = '2'                        
AND ct.site_id = '1'
GROUP BY ct.entry_id 
HAVING MAX(CASE WHEN cp.cat_id IN (119,122) THEN 1 ELSE 0 END) = 1 AND
       MAX(CASE WHEN cp.cat_id IN (129,127) THEN 1 ELSE 0 END) = 1 AND
       MAX(CASE WHEN cp.cat_id IN (140) THEN 1 ELSE 0 END) = 1 
ORDER BY ct.entry_date DESC

1 个答案:

答案 0 :(得分:1)

所以,你似乎有一个table_posts,每个entry_id有多行。您希望entry_id的各行上的类别符合您的条件。

这需要一个having子句:

select cp.entry_id
from category_posts cp left outer join
     group1 g1
     on cp.cat_id = g1.cat_id left outer join
     group2 g2
     on cp.cat_id = g2.cat_id left outer join
     group3 g3
     on cp.cat_id = g3.cat_id
group by cp.entry_id
having max(case when g1.cat_id is not null then 1 else 0 end) = 1 and
       max(case when g2.cat_id is not null then 1 else 0 end) = 1 and
       max(case when g3.cat_id is not null then 1 else 0 end)

也就是说,每组中至少有一个代表性类别。