You need to enable JavaScript to run this app. Flutter使用sqflite如何统计库中不足1年的记录并解决SQL报错
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 15:54:03