njz*_*zk2 18 android group-by android-contentprovider android-contacts
我正在对Android Contacts ContentProvider进行查询.我需要一个Group By子句.在Gingerbread和Honeycomb中,我这样做是为了同时搜索电话号码和电子邮件:
(实际的WHERE子句要复杂得多,因为它包含类型检查.这是一种简化,但它会产生相同的结果)
String request = Phone.NUMBER + " LIKE ? OR " + Email.DATA + " LIKE ?";
String[] params = new String["%test%", "%test%"];
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
new String[] { Data._ID, Data.RAW_CONTACT_ID },
request + ") GROUP BY (" + Data.RAW_CONTACT_ID,
params, "lower(" + Data.DISPLAY_NAME + ") ASC");
Run Code Online (Sandbox Code Playgroud)
注入')'完成WHERE子句并允许插入GROUP BY子句.
但是,在Ice Cream Sandwich中,似乎ContentProvider会检测到这一点,并添加正确数量的括号以防止我的注射.在单个游标查询中执行此操作的任何其他方式?
目前,我已经删除了GROUP BY,并添加了一个MatrixCursor来限制影响,但我宁愿拥有一个真正的游标:
MatrixCursor result = new MatrixCursor(new String[] { Data._ID, Data.RAW_CONTACT_ID });
Set<Long> seen = new HashSet<Long>();
while (cursor.moveToNext()) {
long raw = cursor.getLong(1);
if (!seen.contains(raw)) {
seen.add(raw);
result.addRow(new Object[] {cursor.getLong(0), raw});
}
}
Run Code Online (Sandbox Code Playgroud)
我最近在查询 CallLog.Calls DB 时遇到了这个问题(我们无法修改 ContentProvider)。我们最终要做的是构建一个如下所示的查询:
SELECT _id, date, duration, type, normalized_number FROM calls WHERE _id IN (
SELECT _id FROM calls WHERE date < ? GROUP BY normalized_number ORDER BY date DESC LIMIT ?
);
Run Code Online (Sandbox Code Playgroud)
这里的想法是,我们将任何有效的 sqlite 放入子查询中,返回 id 列表,然后再次查询具有这些 id 的所有调用。
最终的代码看起来像这样:
String whereClause = "_id IN (SELECT _id FROM calls WHERE data < ? GROUP BY normalized_number ORDER BY date DESC LIMIT ?)";
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI,
new String[] { "_id", "date", "duration", "normalized_number" },
whereClause,
new String[]{ String.valueOf(amount), String.valueOf(dateFrom) },
null
);
...
Run Code Online (Sandbox Code Playgroud)
如果您正在查询联系人,它看起来像这样:
String whereClause = "_id IN (SELECT _id FROM contacts WHERE " + Phone.NUMBER + " LIKE ? OR " + Email.DATA + " LIKE ? GROUP BY " + Data.RAW_CONTACT_ID + " ORDER BY lower(" + Data.DISPLAY_NAME + ") ASC)";
String[] params = new String["%test%", "%test%"];
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
new String[] { Data._ID, Data.RAW_CONTACT_ID },
whereClause,
params,
null
);
Run Code Online (Sandbox Code Playgroud)
性能会有所下降(因为我们本质上是为相同的结果查询两次),但它肯定会比查询所有调用并在 java 世界中完成工作要快得多,GROUP BY并且还允许您构建查询带有附加条款。
希望这可以帮助。我们在奥利奥上使用了它,它满足了我们的需求。