在冰淇淋三明治中的ContentResolver中分组

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)

Con*_*son 2

我最近在查询 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并且还允许您构建查询带有附加条款。

希望这可以帮助。我们在奥利奥上使用了它,它满足了我们的需求。