我在基于每天的时间戳汇总数据一周的时间内遇到问题。有一个SQLite数据库,它有一个表,我保存步行数的步骤(timestamp
列是UTC,created_At
是当地时间,但我还是不使用created_at列)。
我想要做的是获取7天前发生的总数据,直到前一天的午夜。所以我有这个jodatime
表达式来查找时间戳的开始和结束
long start = new DateTime().withMillisOfDay(0).minusDays(7).getMillis();
long end = new DateTime().withTimeAtStartOfDay().getMillis();
//start milli:1405029600000 DateTime: 2014-07-11 00:00:00
//end milli:1405634400000 DateTime: 2014-07-18 00:00:00
然后我执行这个sql命令:
SELECT * FROM pa_data WHERE timestamp BETWEEN 1405029600000 AND 1405634400000
而且我很确定它会返回正确的行(我已经在我的电脑上将android数据库结果与SQLite数据库浏览器进行了比较,两者都返回相同的行数)。为此,我尝试使用这个嵌套迭代:
我想要创建的对象是:
public class PhysicalActivityPerDay {
private List<PhysicalActivity> mList;
public PhysicalActivityPerDay(List<PhysicalActivity> list) {
mList = new ArrayList<PhysicalActivity>(list);
}
//methods....
}
现在问题是,我希望有一个数据对象可以保存每天的行。
List<PhysicalActivity> all = getPhysicalActivitiesBetween(start, end);
List<PhysicalActivityPerDay> perDays = new ArrayList<PhysicalActivityPerDay>();
List<PhysicalActivity> tempList;
PhysicalActivityPerDay tempPerDay;
for (int i = 0; i < 7; i++) {
long begin = start;
long stop = (begin + 86400000); //add 24 hours
tempList = new ArrayList<PhysicalActivity>();
for (int j = 0; j < all.size(); j++) {
PhysicalActivity p = all.get(j);
DateTime when = new DateTime(p.getTimestamp());
if (when.isAfter(start) && when.isBefore(stop)) {
tempList.add(p);
all.remove(j); //remove the matching object from the list
}
}
tempPerDay = new PhysicalActivityPerDay(tempList);
perDays.add(tempPerDay);
start += 86400000; //add 24 hours or 1 day for next iteration
}
return perDays;
但结果完全出乎意料。有许多行与上面的if
语句不匹配。我做了一个调试,这就是发生的事情:
Log.w(TAG, "There are totally " + all.size() + " physical activities for day for 7 days");
//There are totally 6559 physical activities for day for 7 days
但是,当我检查all
列表(DB返回的总行数)时,虽然我从中删除匹配的对象,但如果我在嵌套迭代后查询其大小,那么令人惊讶的是它仍包含许多对象,告诉我迭代没有成功!
//Remaining: 3278 records after iterations from 6559
我做错了什么?请帮我看看!
答案 0 :(得分:1)
不确定这是否是唯一的问题:
您正在循环all
列表,并删除项目。
当您致电all.remove(j)
时,过去位于第j + 1位置的项目将移至poisition j。这意味着你的for循环会跳过该项。
解决此问题的一种方法是,只有在您不从列表中删除项目时才增加j。
for (int j = 0; j < all.size();) {
PhysicalActivity p = all.get(j);
DateTime when = new DateTime(p.getTimestamp());
if (when.isAfter(start) && when.isBefore(stop)) {
tempList.add(p);
all.remove(j); //remove the matching object from the list
} else {
j++;
}
}
实际上,我并不完全确定在此修复之后循环是否可行。这取决于在每次迭代中是否评估all.size()
。如果它不是,即使您要删除项目,它也会期望列表具有初始元素数。在这种情况下,当您第一次尝试访问超出数组最后一个索引的索引时,您可能会遇到异常。
如果出现异常,可以用while循环替换循环:
Iterator<PhysicalActivity> iter = all.iterator();
while (iter.hasNext ()) {
PhysicalActivity p = iter.next();
...
if (...) {
iter.remove();
}
}
请参阅definition of List.remove():
public E remove(int index)
删除此列表中指定位置的元素。 向左移动任何后续元素(从索引中减去一个)。
答案 1 :(得分:0)
如何让SQL为您执行聚合
SELECT strftime('%W-%Y',dt) as weekYear, count(1) as occurencePerWeek
FROM SOMETABLE c GROUP BY weekYear;