无法使用 getContentResolver().query() 进行 CASE WHEN 查询
Posted
技术标签:
【中文标题】无法使用 getContentResolver().query() 进行 CASE WHEN 查询【英文标题】:Cannot do a CASE WHEN query using getContentResolver().query() 【发布时间】:2017-12-01 08:43:36 【问题描述】:我正在尝试对设备的联系人执行以下查询:
final String[] PROJECTION =
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,
ContactsContract.CommonDataKinds.Phone.NUMBER,
String.format("CASE WHEN " + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " LIKE '%%%s%%' THEN 'full' END name_match", mFirstName)
;
String SELECTION = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " LIKE ?";
String[] selectionArgs = mFirstName;
String ORDER_BY = "name_match ASC";
Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, ORDER_BY);
但我得到以下异常:
java.lang.IllegalArgumentException: Invalid column CASE WHEN display_name LIKE '%john%' THEN 'full' END name_match at android.database.sqlite.SQLiteQueryBuilder.computeProjection(SQLiteQueryBuilder.java:632) at android.database.sqlite.SQLiteQueryBuilder.buildQuery(SQLiteQueryBuilder.java:447) at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:387) at com.android.providers.contacts.ContactsProvider2.query(ContactsProvider2.java:7812) at com.android.providers.contacts.ContactsProvider2.queryLocal(ContactsProvider2.java:7550) at com.android.providers.contacts.ContactsProvider2.query(ContactsProvider2.java:6037) at android.content.ContentProvider$Transport.query(ContentProvider.java:238) at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112) at android.os.Binder.execTransact(Binder.java:453)
这里有什么问题?是否可以对内容提供者执行 CASE WHEN 查询?在联系人表上?如果没有,是否有其他方法可以进行这样的查询?
谢谢。
【问题讨论】:
你想做什么?为什么不检查选择中的LIKE %?%
呢?放在投影里没意义……
我已经缩短了代码以专注于这个问题。我删除了其他一些 CASE WHEN 条件。我想做的是有另一列将包含名称匹配结果 - 完全匹配/名字匹配/姓氏匹配。
我看了一点 AOSP 代码,在 SQLiteQueryBuilder 上有一个名为 mStrict 的类变量。当设置为 true 时,它不允许在 SELECT 部分中使用除实际表列之外的任何其他内容。当然,联系人提供者将其设置为 true。我不明白...
【参考方案1】:
您可以在代码中轻松完成,而不是在 ContentProvider 中做您想做的事(这似乎不可能):
final String[] projection = ... ;
String selection = Phone.DISPLAY_NAME_PRIMARY + " LIKE %?%";
String[] selectionArgs = mFirstName ;
Cursor cursor = cr.query(Phone.CONTENT_URI, projection, selection, selectionArgs, null);
List<String> fullMatch = new ArrayList<>();
List<String> partialMatch = new ArrayList<>();
while (cursor.moveToNext())
String name = cursor.getString(3); // exact number depends on your projection
if (mFirstName.equalsIgnoreCase(name)
fullMatch.add(name);
else
partialMatch.add(name);
cursor.close();
List<String> allMatches = new ArrayList<>();
allMatches.addAll(fullMatch);
allMatches.addAll(partialMatch);
【讨论】:
以上是关于无法使用 getContentResolver().query() 进行 CASE WHEN 查询的主要内容,如果未能解决你的问题,请参考以下文章
有没有其他方法可以在不使用`getContentResolver()`的情况下访问联系人?
getContentResolver().query()方法selection参数使用详解(转)
getcontentresolver() 在服务中返回 null
Context.managedQuery()和context.getContentResolver()获取Cursor关闭注意事项