SQL查询以获取在日历中确实有事件的用户

时间:2018-10-31 02:49:53

标签: mysql sql

我有以下数据库表:

用户表:

| id  |  name |
| 1   |  bob  |
| 2   |  jane |
| 3   |  tim  |
| 4   |  rex  |

事件表:

| id  | user_id | date       |
| 1   |    1    | 12/05/2018 |
| 2   |    1    | 13/05/2018 |
| 2   |    2    | 15/05/2018 |
| 3   |    2    | 16/05/2018 |
| 4   |    3    | 27/05/2018 |

我想构建一个SQL查询,该查询检索在接下来的7天内确实发生任何事件的所有用户,并且还返回7天中的每一天的一列,其中包含该用户为每一天预订的事件数那些日子。

理想情况下,这就是我想要实现的目标:

| user_id | 12/05/2018 | 13/11/2018 | 14/11/2018 | 15/11/2018 |
| 1       | 1          | 1          | 0          | 0          |
| 2       | 0          | 0          | 0          | 1          |

到目前为止,我已经将此作为起点,但由于返回零行而无法正常工作

SELECT
    users.id,
    name
FROM
    `users`
    inner join bookings on `users`.`id` = bookings.teacher_id
WHERE
    bookings.`date` BETWEEN NOW() AND DATE_ADD( NOW(), INTERVAL 7 DAY )

有人可以帮我实现这一目标吗?甚至可以在1个SQL查询中实现吗?

2 个答案:

答案 0 :(得分:0)

实际上,您需要LEFT JOIN
之所以如此,是因为您希望表'user'中的元素在表预订中没有链接。
使用LEFT JOIN将返回表用户中的所有元素(无论它是否有预订),然后使用WHERE条件过滤并仅保留那些没有预订的用户(booking.id为NULL)

SELECT
    u.id AS userId,
    u.name AS userName
FROM
    `user` AS u
    LEFT JOIN booking AS b ON (
            u.id = b.userId
            AND b.`date` BETWEEN NOW() AND DATE_ADD( NOW(), INTERVAL 7 DAY )
        )
WHERE
    ISNULL(b.id)

在sql约定中,表名采用单数形式...在nosql中,这是另一种方式,只是为了混淆一切...

答案 1 :(得分:0)

在不进行硬编码的情况下,很难将列名生成为下一个日期的字符串(例如'2018-11-01','2018-11-02')。

但是我可以给出一个答案,其中列名被命名为d1..d7。希望你的情况很好。这可能不是最佳解决方案,但可以。

SELECT
  tt.user_id,
  SUM(tt.d1) AS d1,
  SUM(tt.d2) AS d2,
  SUM(tt.d3) AS d3,
  SUM(tt.d4) AS d4,
  SUM(tt.d5) AS d5,
  SUM(tt.d6) AS d6,
  SUM(tt.d7) AS d7
FROM
  (SELECT
   t.user_id,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 1 DAY)) THEN t.total ELSE 0 
END) AS d1,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 2 DAY)) THEN t.total ELSE 0 
END) AS d2,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 3 DAY)) THEN t.total ELSE 0 
END) AS d3,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 4 DAY)) THEN t.total ELSE 0 
END) AS d4,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 5 DAY)) THEN t.total ELSE 0 
END) AS d5,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 6 DAY)) THEN t.total ELSE 0 
END) AS d6,
   (CASE WHEN t.`date` = DATE(DATE_ADD(NOW(), INTERVAL 7 DAY)) THEN t.total ELSE 0 
END) AS d7

  FROM
  (
    SELECT b.user_id, b.`date`, COUNT(*) as total 
    FROM `bookings` b
    WHERE b.`date` BETWEEN NOW() AND DATE_ADD( NOW(), INTERVAL 7 DAY )
    GROUP BY b.user_id, b.`date`) t
  ) tt

 GROUP BY tt.user_id

此查询为您提供的表给我这样的结果。

| user_id | d1 | d2 | d3 | d4 | d5 | d6 | d7 |
----------------------------------------------
|    1    | 1  | 0  | 0  | 0  | 0  | 0  | 0  |
|    2    | 0  | 1  | 1  | 0  | 0  | 0  | 0  |
|    3    | 0  | 0  | 0  | 0  | 1  | 0  | 0  |

第二天d1的意思是。 d2表示后天,等等。

此解决方案还为列也提供了全零(即没有任何事件的天数)