无法使用 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

getcontentresolver() 未为该类型定义

Context.managedQuery()和context.getContentResolver()获取Cursor关闭注意事项

无法获取联系人姓名