在单个 SELECT 中获取条件计数和条件 DISTINCT 计数
Get conditional count and conditional DISTINCT count in a single SELECT
我有 3 个 table:
TABLE: session_log
user_id | device | logged_on
---------|--------|---------------------
1 | web | 2022-01-01 12:43:25
1 | web | 2022-01-01 13:33:32
2 | mobile | 2022-01-01 18:20:18
1 | mobile | 2022-01-01 08:22:41
2 | web | 2022-01-01 09:10:16
3 | web | 2022-01-01 07:52:21
1 | web | 2022-01-02 10:42:14
TABLE: standard_users
user_id | username
---------|-----------
1 | adam
2 | jennifer
TABLE: admin_users
user_id | username
---------|-----------
3 | george
我想计算每天和每种设备类型(移动设备或网络)的唯一非管理员(标准)用户的数量。另一个要注意的是,如果用户在同一天同时登录 Web 和移动设备,我仍然希望将它们包括在两种设备类型的计数中,但当天每种设备的计数不超过一次。
从上面的 table 记录中,我想得到的结果计数应该如下所示:
login_date | mobile_count | web_count
------------|--------------|-----------
2022-01-01 | 2 | 2
2022-01-02 | 0 | 1
目前我有一个查询没有考虑唯一用户条件,我很难弄清楚如何修改它以同时考虑每个计数的唯一用户 ID。
SELECT
s.logged_on::date AS login_date,
sum(CASE WHEN s.device = 'mobile' THEN 1 ELSE 0 END) AS mobile_count,
sum(CASE WHEN s.device = 'web' THEN 1 ELSE 0 END) AS web_count,
FROM session_log s
LEFT JOIN standard_users su ON su.user_id = s.user_id
WHERE su.user_id IS NOT NULL
GROUP BY login_date;
我目前的上述查询在上面的示例数据上 运行 时为 web_count 提出了 3,因为它没有计算 user_id 的唯一性所以它在 1 月 1 日两次计算 user_id
为 1 的记录。
有没有办法修改我的查询,以便在执行每个总和时也考虑 user_id
的唯一性?
使用聚合 FILTER
子句。然后你可以将你的计数与 DISTINCT
:
结合起来
SELECT s.logged_on::date AS login_date
, count(*) FILTER (WHERE s.device = 'mobile') AS mobile_count
, count(DISTINCT user_id) FILTER (WHERE s.device = 'web') AS web_count
FROM session_log s
JOIN standard_users su USING (user_id)
GROUP BY login_date;
参见:
- Aggregate columns with additional (distinct) filters
我还用 LEFT JOIN
和 IS NOT NULL
简化了你扭曲的公式。归结为一个普通的 JOIN
.
如果 session_log.user_id
和 standard_users.user_id
之间的引用完整性是通过 FK 约束强制执行的,并且 standard_users.user_id
被定义为 UNIQUE 或 PK - 看起来很合理 - 你可以删除 JOIN
完全:
SELECT logged_on::date AS login_date
, count(*) FILTER (WHERE device = 'mobile') AS mobile_count
, count(DISTINCT user_id) FILTER (WHERE device = 'web') AS web_count
FROM session_log
GROUP BY 1;
我有 3 个 table:
TABLE: session_log
user_id | device | logged_on
---------|--------|---------------------
1 | web | 2022-01-01 12:43:25
1 | web | 2022-01-01 13:33:32
2 | mobile | 2022-01-01 18:20:18
1 | mobile | 2022-01-01 08:22:41
2 | web | 2022-01-01 09:10:16
3 | web | 2022-01-01 07:52:21
1 | web | 2022-01-02 10:42:14
TABLE: standard_users
user_id | username
---------|-----------
1 | adam
2 | jennifer
TABLE: admin_users
user_id | username
---------|-----------
3 | george
我想计算每天和每种设备类型(移动设备或网络)的唯一非管理员(标准)用户的数量。另一个要注意的是,如果用户在同一天同时登录 Web 和移动设备,我仍然希望将它们包括在两种设备类型的计数中,但当天每种设备的计数不超过一次。
从上面的 table 记录中,我想得到的结果计数应该如下所示:
login_date | mobile_count | web_count
------------|--------------|-----------
2022-01-01 | 2 | 2
2022-01-02 | 0 | 1
目前我有一个查询没有考虑唯一用户条件,我很难弄清楚如何修改它以同时考虑每个计数的唯一用户 ID。
SELECT
s.logged_on::date AS login_date,
sum(CASE WHEN s.device = 'mobile' THEN 1 ELSE 0 END) AS mobile_count,
sum(CASE WHEN s.device = 'web' THEN 1 ELSE 0 END) AS web_count,
FROM session_log s
LEFT JOIN standard_users su ON su.user_id = s.user_id
WHERE su.user_id IS NOT NULL
GROUP BY login_date;
我目前的上述查询在上面的示例数据上 运行 时为 web_count 提出了 3,因为它没有计算 user_id 的唯一性所以它在 1 月 1 日两次计算 user_id
为 1 的记录。
有没有办法修改我的查询,以便在执行每个总和时也考虑 user_id
的唯一性?
使用聚合 FILTER
子句。然后你可以将你的计数与 DISTINCT
:
SELECT s.logged_on::date AS login_date
, count(*) FILTER (WHERE s.device = 'mobile') AS mobile_count
, count(DISTINCT user_id) FILTER (WHERE s.device = 'web') AS web_count
FROM session_log s
JOIN standard_users su USING (user_id)
GROUP BY login_date;
参见:
- Aggregate columns with additional (distinct) filters
我还用 LEFT JOIN
和 IS NOT NULL
简化了你扭曲的公式。归结为一个普通的 JOIN
.
如果 session_log.user_id
和 standard_users.user_id
之间的引用完整性是通过 FK 约束强制执行的,并且 standard_users.user_id
被定义为 UNIQUE 或 PK - 看起来很合理 - 你可以删除 JOIN
完全:
SELECT logged_on::date AS login_date
, count(*) FILTER (WHERE device = 'mobile') AS mobile_count
, count(DISTINCT user_id) FILTER (WHERE device = 'web') AS web_count
FROM session_log
GROUP BY 1;