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

PostgreSQL多条件查询:筛选仅晚到未正常签到的用户数据

解决PostgreSQL中排除已有早时段签到记录的晚到用户查询问题

嘿,我发现你当前的查询返回空结果的核心问题了——你的NOT EXISTS子查询没有和外层查询的用户ID做关联!

原查询里的子查询只是检查整个checkinout表在2017-12-28 06:15:00到2017-12-28 07:45:00之间有没有任何记录,只要存在哪怕一条,NOT EXISTS就会返回false,直接把主查询里所有符合晚时段条件的用户都排除掉了,这显然不是你想要的逻辑。

你的需求是要找出:在晚时段(07:45-13:45)有签到,且同一个用户在早时段(06:15-07:45)完全没有签到记录的人,对吧?那我们需要修正子查询,让它针对每个用户单独检查早时段的签到情况。

修正后的查询(NOT EXISTS版本)

SELECT DISTINCT ON (co.userid) co.userid, ui.name
FROM checkinout co
JOIN userinfo ui ON ui.userid = co.userid
WHERE co.checktime BETWEEN '2017-12-28 07:45:00' AND '2017-12-28 13:45:00'
AND NOT EXISTS (
    SELECT 1  -- EXISTS只关心存在性,选1比选字段更高效
    FROM checkinout co_early
    WHERE co_early.userid = co.userid  -- 关键:关联外层的用户ID,确保检查同一个用户
      AND co_early.checktime BETWEEN '2017-12-28 06:15:00' AND '2017-12-28 07:45:00'
);

关键修正点

  • 给子查询的checkinout表起了别名co_early,并添加co_early.userid = co.userid的关联条件,这样子查询只会检查当前用户(外层查询的用户)在早时段有没有签到记录
  • 子查询用SELECT 1代替SELECT co.userid,因为EXISTS只判断是否存在匹配记录,不需要返回具体字段,这样性能更优
  • 保留DISTINCT ON (co.userid),确保同一个用户在晚时段有多次签到时,只返回一条记录

另一种实现方式(LEFT JOIN + IS NULL)

如果你习惯用JOIN的写法,也可以用左连接后判断空值的方式实现相同逻辑:

SELECT DISTINCT ON (co.userid) co.userid, ui.name
FROM checkinout co
JOIN userinfo ui ON ui.userid = co.userid
LEFT JOIN checkinout co_early
    ON co_early.userid = co.userid
    AND co_early.checktime BETWEEN '2017-12-28 06:15:00' AND '2017-12-28 07:45:00'
WHERE co.checktime BETWEEN '2017-12-28 07:45:00' AND '2017-12-28 13:45:00'
AND co_early.userid IS NULL;  -- 说明该用户没有早时段的签到记录

这两种写法在PostgreSQL中的性能表现基本一致,你可以根据自己的代码习惯选择。

内容的提问来源于stack exchange,提问作者Alvian Cahyadi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:38:03