一、背景
有些场景希望不同日期时间增量获取不同的数据,比如 想要早上9:30更新昨天的数据,凌晨更新全月的数据,另外每月1-9号的凌晨要更新上个月和本月的数据。但是数据集定时更新设置不支持这样的判断设置,就需要借助模型结构sql条件判断实现。
二、案例
以
resource_role_rel
表为例,业务需求要求根据当前日期和时间动态动态调整增量更新sql,以获取符合特定时间范围的记录。具体需求如下:- 每月 1 - 9 号早上 9 点半前,查询创建时间大于上月第一天的记录。
- 日期大于 9 号,早上 9 点半之前,查询创建时间大于本月第一天的记录。
- 早上 9 点半之后,查询创建时间等于昨天的记录。
三、实现思路
为了实现上述需求,我们将使用 SQL 语句结合 MySQL 提供的日期和时间函数来动态生成查询条件。主要思路是根据当前日期和时间进行条件判断,然后使用
OR
逻辑将不同的条件组合起来,确保满足任意一个条件的记录都能被查询出来。SELECT *
FROM `resource_role_rel`
WHERE
(
-- 每月 1 - 9 号早上 9 点半前,创建时间大于上月第一天
DAY(NOW()) BETWEEN 1 AND 9
AND (HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
AND `ctime` > DATE_SUB(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 MONTH)
)
OR (
-- 日期大于 9 号,早上 9 点半之前,创建时间大于本月第一天
DAY(NOW()) > 9
AND (HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
AND `ctime` > DATE_FORMAT(CURDATE(), '%Y-%m-01')
)
OR (
-- 早上 9 点半之后,创建时间等于昨天
(HOUR(NOW()) > 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) >= 30))
AND `ctime` >= CURDATE() - INTERVAL 1 DAY AND `ctime` < CURDATE()
);
四、代码详细解释
1. 第一个条件块
(
DAY(NOW()) BETWEEN 1 AND 9
AND (HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
AND `ctime` > DATE_SUB(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 MONTH)
)
)
DAY(NOW()) BETWEEN 1 AND 9
:使用DAY(NOW())
函数获取当前日期是当月的第几天,通过BETWEEN
操作符判断是否在 1 到 9 之间,确保只在每月 1 - 9 号进行该条件的查询。(HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
:通过HOUR(NOW())
和MINUTE(NOW())
函数分别获取当前时间的小时和分钟,判断当前时间是否在早上 9 点半之前。ctime > DATE_SUB(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 MONTH)
:DATE_FORMAT(CURDATE(), '%Y-%m-01')
将当前日期格式化为当前月的第一天,DATE_SUB(..., INTERVAL 1 MONTH)
从当前月第一天减去一个月得到上个月的第一天,最后判断ctime
字段是否大于上个月的第一天。
2. 第二个条件块
(
DAY(NOW()) > 9
AND (HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
AND `ctime` > DATE_FORMAT(CURDATE(), '%Y-%m-01')
)
DAY(NOW()) > 9
:判断当前日期是否大于 9 号。(HOUR(NOW()) < 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) < 30))
:同样判断当前时间是否在早上 9 点半之前。ctime > DATE_FORMAT(CURDATE(), '%Y-%m-01')
:判断ctime
字段是否大于本月第一天。
3. 第三个条件块
(
(HOUR(NOW()) > 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) >= 30))
AND `ctime` >= CURDATE() - INTERVAL 1 DAY AND `ctime` < CURDATE()
)
(HOUR(NOW()) > 9 OR (HOUR(NOW()) = 9 AND MINUTE(NOW()) >= 30))
:判断当前时间是否在早上 9 点半之后。ctime >= CURDATE() - INTERVAL 1 DAY AND ctime < CURDATE()
:CURDATE() - INTERVAL 1 DAY
得到昨天的日期,通过该条件判断ctime
字段是否等于昨天。
4. OR
逻辑
三个条件块通过
OR
连接,只要满足其中一个条件的记录就会被查询出来,从而实现了根据不同日期和时间动态筛选数据更新数据集的需求。五、注意事项
- 数据库时间设置:确保 MySQL 服务器的时间设置正确,否则可能会导致日期和时间判断不准确。
ctime
字段类型:ctime
字段应为日期或时间类型,否则可能会导致比较结果不符合预期。可以换成数据集中其他用来和当前时间判断的日期字段。- 性能考虑:如果本地数据库表数据量较大,建议在
ctime
字段上创建索引,以提高查询性能。 - 抽取数据集更新前清理,可以结合前置清理规则和增量更新设置。数据集定时更新设置为按日更新,9点半之前更新一次,9点半之后更新一次,实现不同数据获取更新的需求。
- 如果希望实时获取最新数据,可以在直连数据集模型结构sql中使用,勾选支持实时卡片数据+无缓存,实时实时查询的效果。
- 直连数据集缓存策略参考:https://docs.guandata.com/product/bi/428134461289267200