我遇到了SQL查询问题。我的模式描述了articles
表中的文章与categories
表中的类别之间的多对多关系 - 中间表article_category
具有id
,{{1 }和article_id
字段。
我想选择所有仅包含ID category_id
和1
类别的文章。不幸的是,此查询还将选择除了其他任何类别之外还包含这些类别的任何文章。
例如,这是SQL的示例输出(,为了描述目的显示了类别)。您可以看到,当查询选择了ID为2
的文章时,它还选择了ID为10
的文章,尽管有一个额外的类别。
11
这是我要通过选择仅包含类别+-------+------------+
| id | categories |
+-------+------------+
| 10 | 1,2 |
| 11 | 1,2,3 |
+-------+------------+
和1
的文章来实现的输出。
2
同样,这是我想要选择仅包含类别+-------+------------+
| id | categories |
+-------+------------+
| 10 | 1,2 |
+-------+------------+
,1
和2
的文章的输出。
3
这是我写的SQL。为实现上述目标,我缺少什么?
+-------+------------+
| id | categories |
+-------+------------+
| 11 | 1,2,3 |
+-------+------------+
非常感谢!
答案 0 :(得分:3)
假设您想要的不仅仅是文章的ID:
SELECT a.id
,a.other_stuff
FROM articles a
JOIN article_category ac
ON ac.article_id = a.id
GROUP BY a.id
HAVING GROUP_CONCAT(DISTINCT ac.category_id ORDER BY ac.category_id SEPARATOR ',') = '1,2'
如果你想要的只是文章的id,那么试试这个:
SELECT article_id
FROM article_category
GROUP BY article_id
HAVING GROUP_CONCAT(DISTINCT category_id ORDER BY category_id SEPARATOR ',') = '1,2'
在http://sqlfiddle.com/#!2/9d213/4
中查看此操作还应该补充一点,这种方法的优点是它可以支持检查任意数量的类别,而无需更改查询。只需将'1,2'设为字符串变量,然后更改传递给查询的内容。因此,您可以通过传递“1,2,7”字符串轻松搜索类别为1,2和7的文章。不需要额外的连接。
答案 1 :(得分:1)
您可以在category_id
然后GROUP_CONCAT上加入category.id
以获取所有类别,就像您在解释中所写的那样(第1张表格),而不是使用HAVING
与任何类别匹配设置你喜欢(例子中的'1,2')
使用该方法,您可以使用php或任何其他语言轻松地使此查询动态
SELECT articles.id
FROM articles
WHERE EXISTS (
SELECT GROUP_CONCAT(c.id) AS grp
FROM article_category
LEFT OUTER JOIN categories AS c ON c.id = article_category.category_id
WHERE articles.id = article_id
GROUP BY article_id
HAVING grp = '1,2'
)
答案 2 :(得分:1)
请使用以下查询您可以使用简单查询执行操作。
SELECT a.id, a.name
FROM articles a, categories c, articles_categories ac
WHERE
a.id = ac.article_id AND c.id = ac.category_id
AND c.id = 1 OR c.id = 2;
注意 - 如果两个表之间有多对多关系从article_category表中删除ID并使用article_id和category_id创建复合主键。
谢谢。
答案 3 :(得分:0)
我希望使用group by
和having
来处理这些查询。这是一个例子:
select ac.article_id
from article_category ac
group by ac.article_id
having sum(case when category_id = 1 then 1 else 0 end) > 0 and
sum(case when category_id = 1 then 2 else 0 end) > 0;
having
子句中的每个条件都在测试是否存在其中一个类别。
我发现这种方法最灵活,可以回答许多不同类型的" set-within-sets"问题。
编辑:
上述内容略有不同可能更容易生成:
having sum(category_id in (1, 2, 3)) = count(*) and
count(*) = 3
假设数据中没有重复项,这将起作用。您需要将3
更新为in
列表中的项目数。
答案 4 :(得分:0)
也许,比如:
select distinct article_id from article_cathegory
where category_id in (1,2)
minus
select distinct article_id from article_cathegory
where category_id not in (1,2)
答案 5 :(得分:0)
看起来简单的解决方案可能如下:
SELECT
ac.article_id
, SUM(ac.category_id IN (1, 2)) AS nb_categories
, COUNT(ac.category_id) AS nb_all_categories
FROM
article_categories ac
GROUP BY
ac.article_id
HAVING
nb_categories=2 AND nb_all_categories=2
在这里,我计算了我们拥有的所需类别数量,并计算了我们总共有多少类别。我们只需要两个类别,因此必需和总数应该等于2.
这非常灵活,添加更多类别只需在HAVING语句中更改类别列表和数字。
答案 6 :(得分:0)
SELECT articles.id
FROM articles
INNER JOIN articles_category ac ON articles.id = ac.article_id
WHERE articles.id IN (
SELECT ac1.article_id
FROM article_category ac1
WHERE ac1.category_id = 1;
)
AND ac.article_id = 2;
AND articles.id NOT IN (
SELECT ac2.article_id
FROM article_category ac2
WHERE ac2.category_id NOT IN (1, 2)
)
远非我写过的最漂亮的一个。
基本上,它首先通过类别ID为1的ID进行限制,然后确保记录的类别为2,最后确保它没有任何其他类别
答案 7 :(得分:0)
帮助而不是非常改变你的查询,我认为逻辑有一个bug。你不想要存在categegory 1,2的文章。您需要的文章不存在不同于1和2的类别。 谢谢&问候
答案 8 :(得分:0)
在SQL Server中,我会使用INTERSECT和EXCEPT。在MySQL中,试试这个:
SELECT DISTINCT article_id
FROM article_category
WHERE category_id=1
AND article_id IN
(SELECT article_id
FROM article_category
WHERE category_id=2)
AND article_id NOT IN
(SELECT article_id
FROM article_category
WHERE category_id NOT IN (1,2))
答案 9 :(得分:0)
使用此SQL查询。
SELECT articles.id
FROM articles
WHERE articles.id in (
SELECT *
FROM article_category,articles
WHERE article_category.articles.id = articles.article_id AND article_category.category_id IN (1,2)
)