2014-07-24 76 views
2

我有兩個表:書籍和USERS_BOOKS:一個SELECT語句中的值

書:

| ID | BOOKNAME | 
|----|----------| 
| 1 | Book1 | 
| 2 | Book2 | 
| 3 | Book3 | 
| 4 | Book4 | 
| 5 | Book5 | 

USERS_BOOKS:

| ID | USERID | BOOKID | STATUS | 
|----|--------|--------|--------| 
| 1 | 001 |  1 | Read | 
| 2 | 001 |  2 | Read | 
| 3 | 001 |  3 | Added | 
| 4 | 002 |  1 | Added | 
| 5 | 002 |  5 | Added | 
| 6 | 003 |  2 | Read | 
| 7 | 004 |  4 | Read | 

http://sqlfiddle.com/#!2/9cff9/1

從這個sqlfiddle我可以查詢書籍列表和讀取它們的人數。

 select BOOKS.ID, BOOKS.BOOKNAME, 
      SUM(CASE WHEN USERS_BOOKS.STATUS='Read' THEN 1 ELSE 0 END) AS NUM_READ 
     from BOOKS 
    LEFT JOIN USERS_BOOKS ON USERS_BOOKS.BOOKID = BOOKS.ID 
    GROUP BY BOOKS.ID 

http://sqlfiddle.com/#!2/9cff9/1

我需要添加到這個查詢的是,我想看看如果特定用戶(用戶標識001)閱讀這些書籍或沒有。因此,在第四列中,我想展示我閱讀第一本書(YES),閱讀第二本書NOTREAD第三本,第四本和第五本書(NO)。 (一個人讀了第四本書,但那不是我)。

期望的結果:

| ID | BOOKNAME| NUM_READ | DID_I_READ_IT| 
|----|---------|----------|--------------| 
| 1 | BOOK1 | 1  |  YES  | 
| 2 | BOOK2 | 2  |  YES  | 
| 3 | BOOK3 | 0  |  NO  | 
| 4 | BOOK4 | 1  |  NO  | 
| 5 | BOOK5 | 0  |  NO  | 
+0

那麼最新?爲查詢中的兩個字段? –

+0

是的,這兩個是用戶標識和狀態。我在@Ollie Jones的回答中對此進行了澄清。這是否更清楚? – erdomester

+0

通常使用http://sqlfiddle.com/來創建這些類型的東西很有用。但是,您將示例數據作爲圖像呈現,並將示例結果集作爲php轉儲,因此很難進行實驗。如果您提供您想要的結果,這可能會有所幫助 –

回答

0

感謝您說明您的問題。首先,讓我們考慮一下將查明特定用戶(例如「001」)是否閱讀特定書籍的查詢。此查詢(http://sqlfiddle.com/#!2/9cff9/13/0)爲用戶列出了他們至少閱讀過一次書籍的用戶列表。

select DISTINCT USERID, 
        BOOKID 
    FROM USERS_BOOKS 
    WHERE STATUS = 'Read' 
     AND USERID='001' 

現在,您需要將此查詢加入到您擁有的查詢中,並選擇一個特定的用戶。這裏的訣竅是要認識到一個查詢/子查詢/ 虛擬表和物理表可以互換使用

所以你得到這個複合查詢(http://sqlfiddle.com/#!2/9cff9/19/0)給你你想要的。這有點複雜,因爲您需要對數據進行兩種截然不同的整理,並將它們結合在一起。當聚合不同時,你需要用不同的子查詢來計算它們。

SELECT a.ID, a.BOOKNAME, a.NUM_READ, 
      CASE WHEN b.BOOKID IS NULL THEN 'NOTREAD' ELSE 'READ' END AS DID_I_READ_IT 
    FROM (/* first subquery */ 
      select BOOKS.ID, BOOKS.BOOKNAME, 
        SUM(CASE WHEN USERS_BOOKS.STATUS='Read' THEN 1 ELSE 0 END) AS NUM_READ 
       from BOOKS 
     LEFT JOIN USERS_BOOKS ON USERS_BOOKS.BOOKID = BOOKS.ID 
      GROUP BY BOOKS.ID, BOOKS.NAME 
     ) AS a 
LEFT JOIN (/* second subquery */ 
      select DISTINCT USERID, 
          BOOKID 
         FROM USERS_BOOKS 
         WHERE STATUS = 'Read' 
         AND USERID = '001' 
     ) AS b ON a.ID = b.BOOKID 

注意,如果你願意,在LEFT JOIN /爲,在「NOTREAD」狀態你要跟規範要求NULL模式。

另請注意,您仍然在使用GROUP BY。我在我的答案中解決了它。

+0

嗯,我不知道我理解你的代碼,但它的工作原理。這不是新手級別。感謝您花時間幫助我!順便說一句,是不是有一個更簡單的方法來做到這一點? – erdomester

+0

@ erdomester,當!我討厭發佈人們不理解的代碼。這不是重點。我希望你花一點時間來試圖看看這個SQL是如何從兩個獨立的虛擬表格中構建出來的子查詢。至於你的問題,有沒有一種「更容易」的方法?也許,但它可能依賴於技巧。這種方式旨在教會如何構建來自不同聚合的結果集。 –

+0

我仍在處理這個。我設法將其定製爲我的目標,但這並不容易。 – erdomester

1

您濫用GROUP BY和MySQL的惡性不好的特性就是迷惑你。閱讀:http://dev.mysql.com/doc/refman/5.5/en/group-by-extensions.html

以標準方式使用GROUP BY,您的結果將更容易預測。如果您使用標準GROUP BY,則SELECT子句中的每個項目必須在GROUP BY子句中命名,或者在SUM()之類的集合函數中命名。

您的結果集中的DID_I_ADD_IT列不是這樣。我不完全理解你想要做什麼,但你可能嘗試改變該列的代碼如下:

GROUP_CONCAT(DISTINCT CASE WHEN USERS_BOOKS.USERID=? AND USERS_BOOKS.STATUS = ? 
           THEN 'Yes' ELSE 'No' END) AS DID_I_ADD_IT 

這將數據移動到一個聚合函數。

你也應該改變你的GROUP BY這樣:

GROUP BY BOOKLIST.ID, BOOKLIST.BOOK_NAME 
+0

我想實現的目標是列出書籍,我可以看到有多少人添加了它們,以及我是否添加了它們。這是否更清楚? – erdomester

+0

例如:根據上表BOOKID 0002是由1人添加,由1人完成,我添加了它。 BOOKID 0003由1人添加,由0人完成,我添加了它。 BOOKID 0005由2人添加,由0人完成,我沒有添加它。 – erdomester

+0

Hi Ollie。我簡化了這個問題,併爲這個問題創建了一個sqlfiddle。你現在明白我想要做什麼嗎?這是我的個人項目(沒有工作或家庭作業),並且我對sql知識有限(尚未)。 – erdomester