SQL查询结果差异求助:为何第二条查询未包含20200131日期?
我来帮你拆解这个问题——两条SQL查询结果差异的核心在于日期时间的比较方式不同,这直接导致第二条查询漏掉了2020年1月31日的大部分数据。
关键差异点对比
先看两条查询的WHERE条件中关于start_time的过滤逻辑:
第一条SQL的过滤:
to_char(start_time,'YYYYMMDD') >= '20200101' and to_char(start_time,'YYYYMMDD') <= '20200131'
这里是把start_time(应该是DATE或TIMESTAMP类型)转成YYYYMMDD格式的字符串,只要日期部分是1月1日到1月31日之间的所有记录都会被包含,不管具体的时分秒。
第二条SQL的过滤:
start_time >= '20200101' and start_time <= '20200131'
这里直接用日期时间类型的start_time和字符串'20200131'比较,数据库会自动把字符串转换成日期时间类型。绝大多数数据库会把'20200131'解析成2020-01-31 00:00:00这个时间点。这就意味着,只有start_time等于或早于这个时间点的记录才会被包含——而1月31日当天00:00之后产生的所有记录(比如2020-01-31 08:30:00)都会被排除在外,这就是你看不到1月31日数据的原因。
解决办法
要让第二条SQL正确包含1月31日全天的数据,有两种常用的修正方式:
方式1:转换start_time为日期字符串(和第一条保持一致逻辑)
把start_time转成YYYYMMDD格式后再比较,这样就能和第一条的过滤逻辑完全对齐:
select SERVER, APP, sum(case when ended_status = 16 then 1 else 0 end) OK, sum(case when ended_status = 32 then 1 else 0 end) BAD, count(ended_status) TOTAL from EXECUTIONS where to_char(start_time,'YYYYMMDD') >= '20200101' and to_char(start_time,'YYYYMMDD') <= '20200131' and SERVER in ('PRO','PRE','DE') group by SERVER, APP order by SERVER,APP;
方式2:调整结束时间为次月第一天的0点(更高效的写法)
如果start_time是索引字段,转字符串可能会导致索引失效,更推荐用日期范围的方式,把结束条件设为次月第一天的0点,这样不需要转换字段就能利用索引:
select SERVER, APP, sum(case when ended_status = 16 then 1 else 0 end) OK, sum(case when ended_status = 32 then 1 else 0 end) BAD, count(ended_status) TOTAL from EXECUTIONS where start_time >= to_date('20200101','YYYYMMDD') and start_time < to_date('20200201','YYYYMMDD') and SERVER in ('PRO','PRE','DE') group by SERVER, APP order by SERVER,APP;
这种写法的好处是,数据库可以直接使用start_time上的索引,查询效率更高,同时能精准包含1月1日00:00:00到1月31日23:59:59的所有记录。
额外提示
以后处理日期范围查询时,尽量避免直接用<=当月最后一天的字符串,因为很容易因为时间部分的问题漏掉数据。优先选择<次月第一天的写法,或者确保日期转换逻辑一致。
内容的提问来源于stack exchange,提问作者absolute333

