本文将讨论几个数据查询相关的主题,包括日期和时间的查询、按正则表达式查询、where和having、查询结果作为数据源和查询条件、随机抽取数据记录。
前一篇文章介绍了MySQL数据库中的日期和时间数据类型、常用操作及相关函数,这里将讨论日期和时间数据的查询及相关应用。
一般来讲,日期和时间查询有两种情况。一种情况是查询某一时间段的数据;另一种是查询时间点,下面分别讨论。
查询时间段时,应注意日、时、分、秒等在交替时存在临界点,如每天的24点就是次日的0点,而时钟是没有24点的,所以,完整的一天应该是大于等于0点,而且小于次日0点的区间,如果是以天为单位的时间段查询条件,可以参考如下代码。
where fdate>='2026-4-13' and fdate<'2026-4-18'
此代码可以完整匹配2026年4月13到2026年4月17日的查询条件。
时间的查询也是这样,如下面的代码可以查询6点到13点以前的时间段。
where ftime>='06:00:00' and ftime<'13:00:00'
按日期和时间中的某一要素查询时(如某年、某月、某日、几点几分等),对于日期和时间类型的数据字段,只需要使用特定的函数读取相应的数据作为条件,如查询2026年3月的记录可以参考如下条件。
where year(fdate)=2026 and month(fdate)=3
如果数据是日期和时间的标准格式,也可以通过like条件进行匹配,如下面的代码同样台要查询2026年3月的数据。
where fdate like '2026-03-%'
如果数据库只是用于简单的数据处理,对性能可能没有太多的要求,但需要注意,函数的调用和计算是有性能代价的,如果数据量大,频繁使用函数和计算时性能会有明显下降。实际应用中,如果记录只是需要保存日期和时间的某一部分数据,同时又只需要按特定的要素进行查询,如按年、按月、按季度、按日等要素查询,也可以通过整数类型的字段保存这些数据,在查询时可以直接调用,如下面的代码。
where f_year=2026 and f_month=3
本例,假设f_year字段保存了年份数据,f_month字段保存了月份数据,条件中可以直接按这两个字段的数据查询,从而避免了函数调用所带来的性能开销。
日期和时间作为组合数据,其应用是多样化的,也是很灵活的,可以根据应用的特点灵活确定保存的数据类型和数据查询的方法。
以正则表达式作为查询条件时可以使用regexp或rlike关键字,如下面的代码,可以查询t1表中f6字段2025年1、2、3月的数据。
use cdb_demo; select * from t1 where f6 rlike '2025-0[123]-.';
本例,在f6的查询模式中指定月份第2位数据只能是1、2、3,即匹配了01、02、03月的数据。更多正则表达式模式的定义方法可以参考《MySQL中的正则表达式》一文。
在select语句中,where和having子句都用于指定查询条件,它们的区别在于,where子句指定原始数据源的条件,而having子句指定使用group by子句分组后的条件。
下图显示了t2表的数据结构。
下面的代码可以统计各组(f3)性别(f4)为1记录中f5字段数据的平均分。
use cdb_demo; select f3,avg(f5) as f5_avg from t2 where f4=1 group by f3;
代码执行结果如下图所示。
如只返回平均值大于等于70的记录,可以修改代码如下。
use cdb_demo; select f3,avg(f5) as f5_avg from t2 where f4=1 group by f3 having f5_avg>=70;
有两个数据相关的表,如前面文章示例中使用的t3和t3a表,其数据如下图所示。
下面的代码演示了select语句中查询结果作为数据源和查询条件。
use cdb_demo; select * from t3 where f1 in( select f1 from (select f1,avg(f101) as f101_avg from t3a group by f1 having f101_avg>6000) as t3a_tmp );
代码中使用了三层select语句,首先从最里层来看,如下面的代码。
(select f1,avg(f101) as f101_avg from t3a group by f1 having f101_avg>6000) as t3a_tmp
代码的功能是查询t3a表中f101字段数据平均值大于6000的记录,并将查询结果命名为t3a_tmp;其返回字段包含f1和f101_avg。此查询的结果如下图所示。
第二层select语句可以理解为如下代码。
select f1 from t3a_tmp
即从t3a_tmp数据源中读取f1字段的数据,查询结果如下图所示。
最外层的select语句会从t3表中读取记录,其条件是f1字段数据等于t3a_tmp中存在的f1字段值,也就是将t3a_tmp中的f1字段值作为in条件中的值列表。本例最终查询结果如下图所示。
rand()函数可以返回一个大于等于0且小于1的随机浮点数,虽然一般情况下不需要,但也可以使用一个整数参数作为随机数的种子(seek value),请注意,使用相同的种子数时,返回的随机数也会相同,适用于需要复现相同随机数的应用场景。
下面的代码演示了rand()函数的应用。
use cdb_demo; select *,rand() as fr from t3 order by fr limit 1;
本例,首先添加临时的随机数据字段fr,然后按其数据排序,最返回返回一条记录,此代码模拟了抽奖操作。实际应用中,可以根据需要修改limit子句的数值以确定随机抽取记录的数量。