Flutter使用sqflite如何统计库中不足1年的记录并解决SQL报错
报错原因
- 直接拼接字符串格式的日期到SQL语句中未加引号,SQL解析时将
10.06.2021识别为非法的数字运算表达式,触发语法错误 - 标准SQLite没有内置
YEAR()函数,即使补全引号也会报函数不存在的错误 - 原有年份差为1的判断逻辑不符合「距今不足1年」的需求,会出现大量误判:比如当前为2024年5月,2023年1月的记录年份差为1但实际间隔已超过1年,2023年12月的记录年份差为1但实际间隔不足半年,两种场景都会被错误统计
正确实现方案
优先推荐将表中DATUM字段存储为毫秒级整数时间戳,日期计算性能最高,也不会出现格式兼容问题,实现代码如下:
// 计算1年前对应的毫秒时间戳 int oneYearAgoTs = DateTime.now().subtract(const Duration(days: 365)).millisecondsSinceEpoch; // 使用参数化查询,避免语法错误和SQL注入风险 var res = await db.rawQuery( 'SELECT COUNT(*) FROM Shisha_table WHERE DATUM > ?', [oneYearAgoTs] ); int count = Sqflite.firstIntValue(res) ?? 0; return count;
如果必须保留dd.MM.yyyy的字符串存储格式,可以用SQLite内置的strftime函数做格式转换后再比较:
// 生成1年前的dd.MM.yyyy格式日期字符串 DateTime oneYearAgo = DateTime.now().subtract(const Duration(days: 365)); String formatNum(int n) => n.toString().padLeft(2, '0'); String oneYearAgoStr = '${formatNum(oneYearAgo.day)}.${formatNum(oneYearAgo.month)}.${oneYearAgo.year}'; var res = await db.rawQuery( '''SELECT COUNT(*) FROM Shisha_table WHERE strftime('%Y%m%d', substr(DATUM,7,4)||'-'||substr(DATUM,4,2)||'-'||substr(DATUM,1,2)) > strftime('%Y%m%d', substr(?,7,4)||'-'||substr(?,4,2)||'-'||substr(?,1,2)) ''', [oneYearAgoStr, oneYearAgoStr, oneYearAgoStr] ); int count = Sqflite.firstIntValue(res) ?? 0; return count;
注意事项
- 所有SQL参数都要通过
?占位符传入,不要直接拼接字符串到SQL语句中,sqflite会自动处理类型转义和引号问题,从根源避免语法错误 - 涉及频繁日期计算的场景优先用时间戳存储日期,不需要额外做字符串拆分转换,查询性能更高
内容的提问来源于stack exchange,提问作者Dankel
相关产品推荐
相关产品推荐

