在select语句中选择一个值

时间:2014-07-24 15:50:58

标签: php mysql pdo group-by aggregate-functions

我有两张桌子: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      |

2 个答案:

答案 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。我在答案中修正了它。