因为在EXPIRE_DATE上建立了索引,如果在EXPIRE_DATE施加了to_char()的数据库函数,就无法使用该索引,将引发一个全表描述。
所以,还得将开始、结束日期字符串用to_date()数据库函数转换为Date类型,如:
select * from T_USER where EXPIRE_DATE between to_date(<开始日期>,'yyyymmdd') and to_date(<结束日期>,'yyyymmdd')
表 2 CHAR类型日期查询SQL结构
但由于使用了to_date字符串日期转换函数,就必须保证开始日期和结束日期的字符串必须是语义合法日期字符串,如20010101,20020228,如果是语义错误的日期字符串,如20010000,20020299,to_date函数将发生转换错误,致使上面的查询SQL语句运行错误。因此,只有开始日期和结束日期字符串都合法时,才可以使用上式的查询SQL。
如果开始或结束日期未精确到日,即只精通到年或月,如2001,200202,则在应用程序的服务层,必须对日期串进行语义分析,将其补齐到8位合法日期字符串,如开始日期字符串"2001"就必须补齐为"20010101",而结束日期字符串"200202"就必须先补齐为"20020228"(非润年的平月),而这一转换逻辑处理起来是比较费神费力的,一不小心就可能引入一个Bug。
第二个麻烦的问题是,如果开始日期和结束日期为空,SQL语句又该如何构造呢?如果还按照表 2的SQL结构进行构造,那么就必须回答一个问题:最小开始日期和最大的结束日期分别是多少,因为你不能用"00000000"来代表最小的日期,也不能用"99999999"来代表最大的日期。
为了避免回答这个问题,就需要在开始日期和结束日期为空时分别采用不同结构的查询SQL语句:
select * from T_USER where EXPIRE_DATE >= to_date(<开始日期>,'yyyymmdd') 表 3 结束日期条件值为空时
select * from T_USER where EXPIRE_DATE <= to_date(<结束日期>,'yyyymmdd') 表 4 开始日期条件值为空时
综上所述,为了使用在EXPIRE_DATE字段上的索引,DATE类型日期在构造查询SQL上明显比CHAR类型日期复杂,具体表现在以下两点:
1) 需要对日期条件值进行语义分析,以得到精确到日的语义合法的日期字符串。
2) 需要为开始/结束日期条件值均不为空,开始日期条件值为空,结束日期条件值为空三种情况分别构造不同结构的SQL语句,也构造SQL的程序必须对应一个分支。
3、在数据查询上的比较
假设需要以EXPIRE_DATE字段为条件查询T_USER的记录,由于已经在T_USER.EXPIRE_DATE字段上建立了索引,在查询时需要考虑使用该索引。Web的查询界面如下:
日期条件值可以是yyyy、yyyy-mm、yyyy-mm-dd的格式,假如开始日期为2001,结束日期为2002,则表示日期区间为2001-01-01到2002-12-31,如果开始日期为2001,结束日期为2002-02,则表示日期区别为2001-01-01到2002-02-28,以此类推。此外,如果开始日期条件未提供,表示查询所有小于等于结束日期的记录,反之如果结束日期条件未提供,表示查询所有大于等于开始日期的记录。
2) 补尾串:将开始日期字符串末尾用0补齐到8位长度,将结束日期字符串末尾用9补齐到8位长度。特别的,如果开始日期为空,则用00000000代替,而结束日期未提供则用99999999代替。