有两个表格categories
和books
,我想根据给定的类别选择所有图书。
分类表:
cat_id | book_id
----------------
1 | 1
2 | 1
3 | 1
3 | 2
书籍表:
id | name
----------------
1 | abc
2 | def
我已经尝试过SELECT * FROM categories WHERE cat_id IN(1,3)
但是它会返回包含至少一个给定类别的书籍。我想要的是它只返回包含所有类别的书籍,所以它应该只返回book_id = 1的所有(或一行)行,因为它是唯一具有所有给定类别的书。
答案 0 :(得分:3)
每本书实际上有多个条目。如果将 n n 类别分配给该书,则会获得该书的 n 条目。因此,您可以对查询进行分组,并仅选择 n 点击的人:
SELECT T.cat_id, count(*) hits FROM
(
SELECT * FROM categories WHERE cat_id IN(1,3)
) T
GROUP BY T.cat_id
HAVING hits = 2
答案 1 :(得分:3)
尝试:
select book_id
from categories
group by book_id
having sum( ( cat_id in (1,3) )::int ) = 2
或者如果您打算将数组从支持直接传递给它的语言传递给postgres(如下所示:http://fxjr.blogspot.com/2009/05/npgsql-tips-using-in-queries-with.html),请使用:
select book_id
from categories
group by book_id
having sum( ( cat_id = ANY(ARRAY[1,3]) )::int ) = 2
如果您想获得图书名称:
select categories.book_id, books.name
from categories
join books on books.id = categories.book_id
group by categories.book_id
,books.name
having sum( ( categories.cat_id in (1,3) )::int ) = 2
@Evan Carroll,修改查询:
ANSI SQL方式:
select categories.book_id, books.name
from categories
join books on books.id = categories.book_id
group by categories.book_id
,books.name
having count(case when categories.cat_id in (1,3) then 1 end) = 2
没有书名:
select book_id
from categories
group by book_id
having count( case when cat_id in (1,3) then 1 end ) = 2
在同一子句(即having
)中内联条件及其计数值的优点是什么,而不是将条件单独放入where
子句及其计数在having
子句中?...
select book_id
from categories
where category_id in (1,3)
group by book_id
having count(*) = 2
...如果我们在having
子句中内联条件及其计数值,我们可以促进查询,让我们说列出所有类别为1和3或类别为2的书籍和3和4 。面向未来的FTW!此外,组合类别及其计数的测试彼此相邻,加上可读性方面的因素。
为了促进这种查询:
select book_id
from categories
group by book_id
having
count( case when cat_id in (1,3) then 1 end ) = 2
or count( case when cat_id in (2,3,4) then 1 end ) = 3
为了达到性能(有时候,实现性能和可读性;不要混合得好),必须将having子句元素的测试复制到where子句:
select book_id
from categories
where cat_id in (1,2,3,4)
group by book_id
having
count( case when cat_id in (1,3) then 1 end ) = 2
or count( case when cat_id in (2,3,4) then 1 end ) = 3
[编辑]
BTW,这是惯用的MySQL:
select book_id
from categories
group by book_id
having sum( cat_id in (1,3) ) = 2
答案 2 :(得分:1)
另一种替代方法:
SELECT book_id FROM categories WHERE cat_id = 1
INTERSECT
SELECT book_id FROM categories WHERE cat_id = 3;
如果您要匹配两个以上的类别,则可以继续链接INTERSECT。
答案 3 :(得分:0)
加入您需要的每个类别:
SELECT books.*
FROM books
JOIN categories cat1 ON cat1.book_id = books.book_id
JOIN categories cat3 ON cat3.book_id = books.book_id
WHERE cat1.cat_id = 1
AND cat3.cat_id = 3
如果您不想添加内部联接,或者使用WHERE EXISTS(半联接)等效地执行此操作。
答案 4 :(得分:0)
SELECT * FROM
(
SELECT b.id, count(c.cat_id) as cat_count
FROM books AS b
JOIN cats AS c
ON ( b.id = c.book_id )
GROUP BY b.id
) AS t
WHERE t.cat_count = ( SELECT DISTINCT count(cat_id) FROM cat );
这假定一本书不能在同一类别中两次。这将选择任一类别中的所有书籍,计算类别,并确保类别计数是最大类别数。
答案 5 :(得分:-1)
试试这个:
SELECT * FROM books WHERE id IN
(SELECT book_id
FROM categories
GROUP BY book_id
HAVING COUNT(distinct cat_id) = (select count(distinct cat_id) from categories))
编辑:我编辑了查询,以便返回包含问题
中所述的所有类别的书籍