Expo-SQLite查询近5个月销售数据异常,求高效解决方案
解决Expo SQLite柱状图数据查询问题及优化方案
问题分析
你的SQL查询返回month为null,核心原因有两个:
- 月份生成逻辑错误:原CTE中
date('now', '-5 months', '+' || n || ' months')生成的是当前日期往前推5个月开始的连续5个月,并非你需要的当前月及前4个月,且参数拼接方式可能引发日期解析异常,导致m.month为null。 - CASE语句无兜底分支:当
m.month为null时,CASE没有匹配项,直接返回null。
修复后的SQL查询
下面是修正后的查询,确保生成正确的月份范围,同时提前计算月份缩写以减少重复计算:
WITH months AS ( SELECT -- 生成YYYY-MM格式的年月字符串 strftime('%Y-%m', date('now', 'start of month', '-' || (4 - n) || ' months')) AS year_month, -- 直接在CTE中生成月份缩写 CASE strftime('%m', date('now', 'start of month', '-' || (4 - n) || ' months')) WHEN '01' THEN 'Jan' WHEN '02' THEN 'Feb' WHEN '03' THEN 'Mar' WHEN '04' THEN 'Apr' WHEN '05' THEN 'May' WHEN '06' THEN 'Jun' WHEN '07' THEN 'Jul' WHEN '08' THEN 'Aug' WHEN '09' THEN 'Sep' WHEN '10' THEN 'Oct' WHEN '11' THEN 'Nov' WHEN '12' THEN 'Dec' END AS month_name FROM (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) ) SELECT m.month_name AS month, COALESCE(SUM(s.soldPrice * s.quantity), 0) AS total_sales_amount FROM months m LEFT JOIN Sales s ON strftime('%Y-%m', s.date) = m.year_month GROUP BY m.year_month, m.month_name ORDER BY m.year_month;
代码优化
修正代码中的语法错误(import语句缺失闭合单引号),并简化结果处理逻辑:
import * as Sqlite from 'expo-sqlite'; const db = Sqlite.openDatabaseSync('test.db'); const getChartData = async () => { const query = ` WITH months AS ( SELECT strftime('%Y-%m', date('now', 'start of month', '-' || (4 - n) || ' months')) AS year_month, CASE strftime('%m', date('now', 'start of month', '-' || (4 - n) || ' months')) WHEN '01' THEN 'Jan' WHEN '02' THEN 'Feb' WHEN '03' THEN 'Mar' WHEN '04' THEN 'Apr' WHEN '05' THEN 'May' WHEN '06' THEN 'Jun' WHEN '07' THEN 'Jul' WHEN '08' THEN 'Aug' WHEN '09' THEN 'Sep' WHEN '10' THEN 'Oct' WHEN '11' THEN 'Nov' WHEN '12' THEN 'Dec' END AS month_name FROM (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) ) SELECT m.month_name AS month, COALESCE(SUM(s.soldPrice * s.quantity), 0) AS total_sales_amount FROM months m LEFT JOIN Sales s ON strftime('%Y-%m', s.date) = m.year_month GROUP BY m.year_month, m.month_name ORDER BY m.year_month;`; const results = await db.getAllAsync(query); // 直接从查询结果提取labels和dataset,无需额外分支处理 const labels = results.map(row => row.month); const dataset = results.map(row => row.total_sales_amount); console.log(labels, dataset); return [labels, dataset]; };
性能优化建议
- 添加函数索引:为
Sales表的日期字段创建函数索引,大幅加速月份匹配的JOIN操作:
CREATE INDEX IF NOT EXISTS idx_sales_month ON Sales (strftime('%Y-%m', date));
- 规范日期存储格式:
Sales表的date字段必须存储为SQLite可识别的标准格式(如YYYY-MM-DD或YYYY-MM-DD HH:MM:SS),否则strftime函数会返回null,导致JOIN失败。 - 逻辑下沉到SQL层:尽量将数据处理逻辑放在SQL中完成,避免在JavaScript中做额外循环计算,减少数据传输和客户端开销。
内容的提问来源于stack exchange,提问作者coderooz
相关产品推荐
相关产品推荐

