You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将MySQL生成的日期列表与未登录用户统计查询结合

解决方案

你可以将日期生成查询作为主查询,通过关联子查询计算每个月初日期对应的未登录用户数,这并不违反MySQL的子查询限制。

以下是整合后的完整查询:

SELECT 
    month_dates.`Month beginning`,
    (
        SELECT COUNT(DISTINCT id) 
        FROM users 
        WHERE timestamp < month_dates.`Month beginning`
    ) - (
        SELECT COUNT(DISTINCT user_id) 
        FROM logins 
        WHERE timestamp < month_dates.`Month beginning`
    ) AS `Not logged in`
FROM (
    SELECT DATE_FORMAT(date_range.timestamp, "%Y-%m-01") AS `Month beginning`
    FROM (
        SELECT CURDATE() - INTERVAL (a.a + 10*b.a + 100*c.a + 1000*d.a) DAY AS timestamp
        FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d
    ) date_range
    WHERE date_range.timestamp BETWEEN '2022-02-28' AND NOW() 
    GROUP BY DATE_FORMAT(date_range.timestamp, "%Y-%m-01") 
) month_dates
ORDER BY month_dates.`Month beginning` DESC;

关键说明

  • 将日期生成逻辑封装为子查询month_dates,生成所有需要统计的月初日期。
  • 针对每个Month beginning日期,使用两个关联子查询分别计算:
    1. 该日期前注册的总用户数
    2. 该日期前有登录记录的用户数
  • 两者的差值即为截至该月初的未登录用户数。

优化建议(大数据量场景)

如果用户表和登录表数据量较大,关联子查询可能存在性能瓶颈,可改用预聚合+左连接的方式提升效率:

WITH month_dates AS (
    SELECT DATE_FORMAT(date_range.timestamp, "%Y-%m-01") AS `Month beginning`
    FROM (
        SELECT CURDATE() - INTERVAL (a.a + 10*b.a + 100*c.a + 1000*d.a) DAY AS timestamp
        FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
        CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d
    ) date_range
    WHERE date_range.timestamp BETWEEN '2022-02-28' AND NOW() 
    GROUP BY DATE_FORMAT(date_range.timestamp, "%Y-%m-01")
),
user_counts AS (
    SELECT 
        DATE_FORMAT(u.timestamp, "%Y-%m-01") AS month_start,
        COUNT(DISTINCT u.id) AS total_users
    FROM users u
    GROUP BY month_start
    WITH ROLLUP
),
login_counts AS (
    SELECT 
        DATE_FORMAT(l.timestamp, "%Y-%m-01") AS month_start,
        COUNT(DISTINCT l.user_id) AS logged_in_users
    FROM logins l
    GROUP BY month_start
    WITH ROLLUP
)
SELECT 
    md.`Month beginning`,
    COALESCE(SUM(uc.total_users), 0) - COALESCE(SUM(lc.logged_in_users), 0) AS `Not logged in`
FROM month_dates md
LEFT JOIN user_counts uc ON uc.month_start < md.`Month beginning`
LEFT JOIN login_counts lc ON lc.month_start < md.`Month beginning`
GROUP BY md.`Month beginning`
ORDER BY md.`Month beginning` DESC;

这种方式先预聚合每个月的用户注册和登录数据,再通过左连接累加得到截至每个月初的总数,性能表现更优。

内容的提问来源于stack exchange,提问作者Matt Saunders

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 11:42:06