2011-06-25 46 views
1

我的數據庫中有三個表。他們的模式基本上是:Postgres - 多個連接導致我的查詢返回不正確的數據

books: 
id | book_title 

books_tags: 
id | book_id | tag_id 

books_votes: 
id | book_id | vote 

這個想法是能夠搜索書籍和按給定標籤(本例中爲716和101)過濾。在ORDER BY caluse中使用total_votes

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被標記與IDS 716和101

這裏是當我運行與books_votes表的查詢加入所返回的內容:

book_id | total_votes 
---------+------------- 
    3 | 2 
    2 | 3 

回答

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 
+0

這也是錯誤的書籍。當應該有兩個標籤時,它返回一行,並且一行沒有標籤標識。 – dave

+0

好的,我現在將它編輯成我的問題。 – dave

+0

現在唯一的問題是它對標籤過濾有點太寬鬆。書籍ID「2」僅標有一個ID。不是都。另外,第三本書有1票。所以total_votes不應該是0 – dave

4

建立複雜的SQL一步一步來。

這給你的書都有所需的標籤。它只與表格定義一樣可靠。你的表格定義不應該讓一本書有兩次相同的標籤。 (book_id,tag_id)需要一個UNIQUE約束。

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 

你的版本是不行的,因爲它返回錯了書身份證號碼。 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 
相關問題