我有两张桌子:BOOKS和USERS_BOOKS:
书:
| 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
我需要添加到此查询中的是,我想查看特定用户(USERID 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 :(得分:1)
你滥用GROUP BY
并且MySQL的恶意错误让你感到困惑。阅读:http://dev.mysql.com/doc/refman/5.5/en/group-by-extensions.html
以标准方式使用GROUP BY
,您的结果将更加可预测。如果您使用标准SELECT
,则GROUP BY
子句中的每个项目都必须在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
答案 1 :(得分: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 / IS NULL模式生成规范要求的“NOTREAD”状态。
另请注意,您仍然在滥用GROUP BY
。我在答案中修正了它。