PostgreSQL考勤表时间范围去重查询报错:运算符不存在boolean = timestamp
解决PostgreSQL查询报错:operator does not exist: boolean = timestamp without time zone
你的SQL语句报错核心是WHERE子句的语法逻辑混乱,具体看这部分:
a.checktime <= '2017-12-05 08:00:00' IN (SELECT checktime FROM checkinout where checktime >='2017-12-05 03:00:00' AND checktime <='2017-12-05 23:00:00')
这里a.checktime <= '2017-12-05 08:00:00'会返回布尔值(true/false),而IN子句返回的是时间戳集合,PostgreSQL没办法把布尔值和时间戳做比较,自然就触发了类型不匹配的错误。
再结合你的需求:要查询2017-11-11 03:00:00到2017-11-11 08:00:00范围内的打卡数据,且这个小范围属于更大的2017-11-11 03:00:00至2017-11-11 23:00:00区间(其实小范围本身就包含在大区间里,除非你想额外限定用户在大区间内有打卡记录),再加上你用DISTINCT ON (a.userid)想要每个用户只返回一条记录的需求,我给你整理了两种修正方案:
方案1:直接查询小时间范围内的用户唯一打卡记录
如果你的需求就是获取每个用户在2017-12-05 03:00:00到2017-12-05 08:00:00内的一条打卡记录(默认按打卡时间排序取第一条,你可以根据需要调整排序规则):
SELECT DISTINCT ON (a.userid) a.userid, b.name, a.checktime FROM checkinout a LEFT JOIN userinfo b ON a.userid = b.userid WHERE a.checktime >= '2017-12-05 03:00:00' AND a.checktime <= '2017-12-05 08:00:00' ORDER BY a.userid, a.checktime; -- 排序规则决定取用户的哪条记录,比如最早或最晚打卡
方案2:确保用户在大区间内有打卡,再取小范围记录
如果你想先筛选出在2017-12-05 03:00:00至2017-12-05 23:00:00内有打卡的用户,再取他们在小范围内的记录,可以用EXISTS子句实现:
SELECT DISTINCT ON (a.userid) a.userid, b.name, a.checktime FROM checkinout a LEFT JOIN userinfo b ON a.userid = b.userid WHERE a.checktime >= '2017-12-05 03:00:00' AND a.checktime <= '2017-12-05 08:00:00' AND EXISTS ( SELECT 1 FROM checkinout c WHERE c.userid = a.userid AND c.checktime >= '2017-12-05 03:00:00' AND c.checktime <= '2017-12-05 23:00:00' ) ORDER BY a.userid, a.checktime;
小提醒:
DISTINCT ON (column)是PostgreSQL特有的语法,必须配合ORDER BY子句使用,否则返回的分组第一条记录是随机的,结果不可控。- 你的原SQL里写的日期是
2017-12-05,但需求描述里是2017-11-11,记得统一成你实际需要的日期哦。
内容的提问来源于stack exchange,提问作者Alvian Cahyadi
相关产品推荐
相关产品推荐

