我的数据库中有三个表。他们的架构基本上是:
books:
id | book_title
books_tags:
id | book_id | tag_id
books_votes:
id | book_id | vote
这个想法是能够搜索书籍并按给定的标签过滤(在本例中为716和101)。 total_votes
用于ORDER BY caluse。
SELECT
books.id AS books_id, sum(book_votes.vote) AS total_votes
FROM
books
JOIN
-- works fine without this join
book_votes ON books.id = book_votes.book_id
JOIN
books_tags ON books.id = books_tags.book_id
WHERE
books_tags.tag_id IN (716, 101)
GROUP BY
books.id
HAVING
count(books.id) = 2
标签过滤本身效果很好。我可以根据需要在IN子句中添加任意数量的标签ID,它会继续过滤结果,只显示带有这些标签的书籍。完美。
当我将第二个JOIN添加到books_votes
表时,会出现问题。此连接不会产生任何错误,只会导致查询返回错误的数据 - 就像它忽略标记ID一样。
第二次加入有什么问题?
编辑:
这是表中的转储:
books:
id | book_title
----+-----------------
1 | first
2 | second
3 | third book
4 | fourth book
5 | fifth
6 | sixth book
books_tags:
id | book_id | tag_id
----+---------+--------
1 | 1 | 293
2 | 1 | 32
3 | 1 | 370
4 | 2 | 101
5 | 2 | 357
6 | 3 | 554
7 | 3 | 808
8 | 3 | 716
9 | 3 | 101
10 | 4 | 787
11 | 4 | 808
12 | 4 | 322
13 | 5 | 787
17 | 6 | 716
18 | 6 | 554
19 | 6 | 101
books_votes:
id | book_id | vote
----+---------+------
2 | 2 | 1
3 | 3 | 1
4 | 4 | 1
7 | 4 | 1
8 | 2 | 1
11 | 5 | 1
12 | 5 | 1
13 | 1 | 1
这是从我发布的查询返回的数据,当我省略第二个连接(到books_votes)时:
book_id
---------
6
3
如您所见,返回正确的书籍。第6和第3册已使用ID 716和101标记。
这是我在连接books_votes表时运行查询时返回的内容:
book_id | total_votes
---------+-------------
3 | 2
2 | 3
答案 0 :(得分:4)
逐步构建复杂的SQL。
这为您提供了具有所需标签的书籍。它只与表定义一样可靠。您的表定义不应允许一本书具有两次相同的标记。你需要一个UNIQUE约束(book_id,tag_id)。
SELECT book_id
FROM books_tags
WHERE books_tags.tag_id IN (716, 101)
GROUP BY book_id
HAVING COUNT(tag_id) = 2
book_id
--
6
3
您可以在JOIN中使用它。
SELECT books.id
FROM books
INNER JOIN (
SELECT book_id
FROM books_tags
WHERE books_tags.tag_id IN (716, 101)
GROUP BY book_id
HAVING COUNT(tag_id) = 2) bt ON bt.book_id = books.id
book_id
--
6
3
加入投票表应该从结果中删除book_id 6。 (没有6票。)
SELECT books.id
FROM books
INNER JOIN (
SELECT book_id
FROM books_tags
WHERE books_tags.tag_id IN (716, 101)
GROUP BY book_id
HAVING COUNT(tag_id) = 2) bt ON bt.book_id = books.id
INNER JOIN books_votes bv ON bv.book_id = books.id
book_id
--
3
现在您可以将投票列添加到查询中。
SELECT books.id, bv.vote
FROM books
INNER JOIN (
SELECT book_id
FROM books_tags
WHERE books_tags.tag_id IN (716, 101)
GROUP BY book_id
HAVING COUNT(tag_id) = 2) bt ON bt.book_id = books.id
INNER JOIN books_votes bv ON bv.book_id = books.id
book_id vote
--
3 1
最后,你可以总结一下。
SELECT books.id, SUM(bv.vote) AS total_votes
FROM books
INNER JOIN (
SELECT book_id
FROM books_tags
WHERE books_tags.tag_id IN (716, 101)
GROUP BY book_id
HAVING COUNT(tag_id) = 2) bt ON bt.book_id = books.id
INNER JOIN books_votes bv ON bv.book_id = books.id
GROUP BY books.id;
book_id total_votes
--
3 1
您的版本不起作用,因为它返回了错误的图书ID号。 books_votes上的JOIN和WHERE子句的组合不能达到预期的效果。
SELECT books.id AS books_id
FROM books
JOIN books_votes ON books.id = books_votes.book_id
JOIN books_tags ON books.id = books_tags.book_id
WHERE books_tags.tag_id IN (716, 101)
GROUP BY books.id
books_id
--
3
2
包含第2册不是因为它有两个标签,而是因为它有两张选票。
SELECT books.id AS books_id, books_tags.tag_id, books_votes.vote
FROM books
JOIN books_votes ON books.id = books_votes.book_id
JOIN books_tags ON books.id = books_tags.book_id
WHERE books_tags.tag_id IN (716, 101)
ORDER BY books_id, tag_id
book_id tag_id vote
--
2 101 1
2 101 1
3 101 1
3 716 1
答案 1 :(得分:0)
据我了解,您需要所有带有标签716和101的书籍,并且您需要每本书的投票数。
select *,
(select count(*) from book_votes as vts where vts.book_id = bks.id) as vote_count
from books as bks
where
id in
(
select book_id
from books_tags as tgs
where tgs.tag_id in (716, 101)
group by book_id
having count(*) = 2
)
结果:
id book_title vote_count
----------- --------------- -----------
3 third book 1
6 sixth book 0