如何在具有多个 WHERE 条件的单个 SQL 查询中获取多个 COUNT?

How can I get multiple COUNT's in a single SQL query with multiple WHERE conditions?

我需要获取有关网络应用程序用户 activity 的报告。

首先,我有一个 table 来计算用户登录我们的应用程序的次数,如下所示:

user_activity
-----------------------------------------------------
| ID_login | Username | Date       | Hour     | ... |
|---------------------|------------|----------|-----|
|        1 | john     | 2019-03-01 | 08:49:24 | ... |
|        2 | john     | 2019-03-01 | 14:12:49 | ... |
|        3 | jane     | 2019-03-03 | 10:02:31 | ... |
|      ... | ...      | ...        | ...      | ... |
-----------------------------------------------------

我想要做的是有一个报告,它不仅会给我一个设定时间段内每个用户的登录总量。我已经可以做到了。当我尝试获取上一年每个月的报告时,我遇到了困难,其中月份在不同的列中。

我希望我的查询生成的 table 看起来像这样:

user_activity
--------------------------------------------------------
| Username | login_total | login_jan | login_feb | ... |
|------------------------|-----------|-----------|-----|
| john     |        4827 |       164 |       191 | ... |
| james    |        3866 |        92 |       144 | ... |
| jane     |        2979 |       104 |        92 | ... |
| ...      |         ... |       ... |       ... | ... |
--------------------------------------------------------

如您所见,我正在考虑使用 login_total 值来用于 ORDER BY。

这就是我现在所拥有的。

SELECT
    user_activity.Username,
    COUNT(user_activity.ID_login) AS login_total

FROM
    user_activity

WHERE
    user_activity.Date >= '2018-01-01'
    AND
    user_activity.Date <= '2018-12-31'

如何获得另一个包含 COUNT 个但具有不同条件的列?我应该把这些标准放在哪里?我试过使用 IF 语句和 HAVING 语句,但没有用。

我在想这样的事情...?

SELECT
    user_activity.Username,
    COUNT(
        IF
            (user_activity.Date >= '2019-01-01'
            AND
            user_activity.Date <= '2019-01-31')
        user_activity.ID_login) 
        AS login_jan,

    COUNT(
        IF
            (user_activity.Date >= '2019-02-01'
            AND
            user_activity.Date <= '2019-02-28')
        user_activity.ID_login) 
        AS login_feb,
    ...

FROM
    user_activity

似乎也没有用...我是否遗漏了什么?

我们可以做条件聚合,像这样:

SELECT ua.username
     , SUM( ua.date >= '2019-01-01' AND ua.date < '2019-02-01' ) AS login_jan
     , SUM( ua.date >= '2019-02-01' AND ua.date < '2019-03-01' ) AS login_feb
  FROM user_activity ua
 GROUP
    BY ua.username

即使用MySQL shorthand,SUM()聚合内的表达式将被计算为1、0或NULL。我们可以使用 MySQL IF() 函数或更便携的 ANSI SQL CASE 表达式

SELECT ua.username
     , SUM(IF( ua.date >= '2019-01-01' AND ua.date < '2019-02-01' ,1,0)) AS login_jan
     , SUM(IF( ua.date >= '2019-02-01' AND ua.date < '2019-03-01' ,1,0)) AS login_feb
  FROM user_activity ua
 GROUP
    BY ua.username

SELECT ua.username
     , SUM(CASE WHEN ua.date >= '2019-01-01' AND ua.date < '2019-02-01' THEN 1 ELSE 0 END) AS login_jan
     , SUM(CASE WHEN ua.date >= '2019-02-01' AND ua.date < '2019-03-01' THEN 1 ELSE 0 END) AS login_feb
  FROM user_activity ua
 GROUP
    BY ua.username

您正在尝试创建一个 PIVOT table,您可以使用条件聚合在 MySQL 中执行此操作。请注意,您可以使用 MONTH and YEAR 函数简化表达式:

SELECT u.Username,
       COUNT(*) AS login_total,
       SUM(MONTH(u.Date) = 1) AS login_jan,
       SUM(MONTH(u.Date) = 2) AS login_feb,
       ...
       SUM(MONTH(u.Date) = 12) AS login_dec
FROM user_activity u
WHERE YEAR(u.Date) = 2018
GROUP BY u.Username

此查询还利用了以下事实:在数字上下文中 MySQL 将布尔表达式视为 1(真)或 0(假),从而允许我们 SUM 这些值。