【问题标题】:Android: Distinct and GroupBy in ContentResolverAndroid:ContentResolver 中的 Distinct 和 GroupBy
【发布时间】:2010-02-22 23:54:15
【问题描述】:

DISTINCT 和/或GROUPBY 添加到基于ContentResolver 的查询中的正确方法是什么?

现在我必须为每个特殊情况创建自定义 URI。

有没有更好的办法?

(我仍然将 1.5 编程为最小公分母)

【问题讨论】:

    标签: android distinct group-by android-contentresolver


    【解决方案1】:

    你可以在查询 contentResolver 时做一个很好的 hack,使用:

    String selection = Models.SOMETHING + "=" + something + ") GROUP BY (" + Models.TYPE;
    

    【讨论】:

    • 如果您无权访问 ContentProvider 源代码,那就太好了。谢谢。
    • 抱歉是我的错,我将 GROUP BY 与我想区分的列一起使用,我不擅长 SQL
    • 这不再起作用了。有没有办法在 ICS 中选择不同的?
    • “多么可怕的失败”代表设计师 :) 为我工作 - min sdk 15, target sdk 19。一个注意事项:我添加了一个“有”子句。
    【解决方案2】:

    如果您想在多于一列的 SELECT 中使用 DISTINCT,您需要使用 GROUP BY。
    使用 ContentResolver.query 的 Mini Hack:

    Uri uri = Uri.parse("content://sms/inbox");
            Cursor c = getContentResolver().query(uri, 
                new String[]{"DISTINCT address","body"}, //DISTINCT
                "address IS NOT NULL) GROUP BY (address", //GROUP BY
                null, null);
            if(c.moveToFirst()){
                do{
                    Log.v("from", "\""+c.getString(c.getColumnIndex("address"))+"\"");
                    Log.v("text", "\""+c.getString(c.getColumnIndex("body"))+"\"");
    
                } while(c.moveToNext());
            }
    

    此代码从设备收件箱中为每个发件人选择最后一条短信。
    注意:在 GROUP BY 之前,我们总是需要写至少一个条件。 ContentResolver.query 方法中的结果 SQL 查询字符串将:

    SELECT DISTINCT address, body FROM sms WHERE (type=1) AND (address IS NOT NULL) GROUP BY (address) 
    

    【讨论】:

    • 谢谢!你救了我的命:)
    • 注意:具有 distinct 的列必须在投影数组的起始位置
    【解决方案3】:

    由于没有人来回答,我只想告诉我我是如何解决这个问题的。基本上我会为每个案例创建自定义 URI 并在 selection 参数中传递标准。然后在ContentProvider#query 内部,我将识别案例并根据表名和选择参数构造原始查询。

    这是一个简单的例子:

    switch (URI_MATCHER.match(uri)) {
        case TYPES:
            table = TYPES_TABLE;
            break;
        case TYPES_DISTINCT:
            return db.rawQuery("SELECT DISTINCT type FROM types", null);
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        return db.query(table, null, selection, selectionArgs, null, null, null);
    

    【讨论】:

    • @njzk2 如果我理解正确,您是说可以获得实际联系人数据库的实例?
    • @Ilya_Gazman 不,我是说这个解决方案只有在你是实现内容提供者的时候才有效。
    • @njzk2 对不起,知识的运气,但为了实现内容提供者,您需要编写一个服装 rom,对吧?它就像 Android 核心系统的一部分,对吧?
    • @Ilya_Gazman 我们在这里讨论的是内容提供商。如果您有关于联系人的具体问题,请写一个新问题。
    【解决方案4】:

    在您覆盖的 ContentProvider 查询方法中,有一个特定的 URI 映射到使用 distinct。

    然后使用SQLiteQueryBuilder 并调用setDistinct(boolean) 方法。

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder)
    {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    
        boolean useDistinct = false;
    
        switch (sUriMatcher.match(uri))
        {
        case YOUR_URI_DISTINCT:
            useDistinct = true;
        case YOUR_URI:
            qb.setTables(YOUR_TABLE_NAME);
            qb.setProjectionMap(sYourProjectionMap);
            break;
    
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
    
        // If no sort order is specified use the default
        String orderBy;
        if (TextUtils.isEmpty(sortOrder))
        {
            orderBy = DEFAULT_SORT_ORDER;
        }
        else
        {
            orderBy = sortOrder;
        }
        // Get the database and run the query
        SQLiteDatabase db = mDBHelper.getReadableDatabase();
                // THIS IS THE IMPORTANT PART!
        qb.setDistinct(useDistinct);
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
    
        if (c != null)
        {
            // Tell the cursor what uri to watch, so it knows when its source data changes
            c.setNotificationUri(getContext().getContentResolver(), uri);
        }
    
        return c;
    }
    

    【讨论】:

    • 什么是 mDBHelper ؟
    【解决方案5】:

    虽然我没有使用Group By,但我在内容解析器查询中使用了Distinct

    Cursor cursor = contentResolver .query(YOUR_URI, new String[] {"Distinct "+ YOUR_COLUMN_NAME}, null, null, null);

    【讨论】:

    • 如果您只需要一列数据,这很好,但是当您需要多列数据时,您需要使用 GROUP BY
    【解决方案6】:

    在投影中添加 Distinct 关键字也对我有用,但是,它仅在 distinct 关键字是第一个参数时才有效:

    String[] projection = new String[]{"DISTINCT " + DBConstants.COLUMN_UUID, ... };
    

    【讨论】:

      【解决方案7】:

      在某些情况下,我们可以使用“distinct(COLUMN_NAME)”作为选择, 它工作完美。 但在某些情况下,它会导致异常。

      当它导致异常时,我将使用 HashSet 来存储列值....

      【讨论】:

        【解决方案8】:
        // getting sender list from messages into spinner View
            Spinner phoneListView = (Spinner) findViewById(R.id.phone_list);
            Uri uri = Uri.parse("content://sms/inbox");     
            Cursor c = getContentResolver().query(uri, new String[]{"Distinct address"}, null, null, null);
            List <String> list;
            list= new ArrayList<String>();
            list.clear();
            int msgCount=c.getCount();
            if(c.moveToFirst()) {
                for(int ii=0; ii < msgCount; ii++) {
                    list.add(c.getString(c.getColumnIndexOrThrow("address")).toString());
                    c.moveToNext();
                }
            }
            phoneListView.setAdapter(new ArrayAdapter<String>(BankActivity.this, android.R.layout.simple_dropdown_item_1line, list));
        

        【讨论】:

        • 你最好解释一下你的答案
        【解决方案9】:

        当您的投影中有多个列时,您应该这样做:

            val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            val projection = arrayOf(
                "DISTINCT " + MediaStore.Images.Media.BUCKET_ID,
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                MediaStore.Images.Media.BUCKET_ID,
                MediaStore.MediaColumns.DATA
            )
            val groupBySelection = " 1) GROUP BY (${MediaStore.Images.Media.BUCKET_ID}"
            contentResolver.query(
                uri,
                projection,
                null,
                groupBySelection,
                null,
                null
            )
        

        带有右括号和数字“1”的groupBySelection 是一个小技巧,但它工作得非常好

        【讨论】:

          【解决方案10】:

          我创建了一个使用 group by 和 distinct 的实用方法。

          用法

          这里是从 MMS 数据库中选择看不见的thread_id 和最后一条消息日期的示例。

          query(contentResolver= contentResolver,
                  select = arrayOf(Mms.THREAD_ID, "max(${Mms.DATE}) as date"),
                  from = Mms.CONTENT_URI,
                  where = "${Mms.SEEN} = 0",
                  groupBy = "1",
                  orderBy = "2 desc"
                  ).use {
              while (it?.moveToNext() == true){
                  val threadId = it.getInt(0)
                  val date = it.getLong(1)
              }
          }
          

          来源

          fun query(
                  contentResolver: ContentResolver,
                  from: Uri,
                  select: Array<String>,
                  where: String? = null,
                  groupBy: Array<out String>? = null,
                  distinct: Boolean = false,
                  selectionArgs: Array<out String>? = null,
                  orderBy: String? = null,
          ): Cursor? {
              val tmpSelect = select[0]
              val localWhere =
                      if (groupBy == null) where
                      else "${where ?: "1"}) group by (${groupBy.joinToString()}"
              if (distinct) {
                  select[0] = "distinct $tmpSelect"
              }
              val query = contentResolver.query(from, select, localWhere, selectionArgs, orderBy)
              select[0] = tmpSelect
              return query
          }
          

          【讨论】:

            【解决方案11】:

            也许获得不同的值更简单, 尝试在您想要的列名之前添加 DISTINCT 单词到投影表中

            String[] projection = new String[]{
                            BaseColumns._ID,
                            "DISTINCT "+ Mediastore.anything.you.want
            };
            

            并将其用作内容解析器的查询方法的参数!

            希望对你有所帮助,因为前几天我也有同样的问题

            【讨论】:

            • 这对我不起作用。我的代码: String[] projection = new String[] { "DISTINCT" + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME};光标 cur = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 投影, "LENGTH(" + ContactsContract.CommonDataKinds.Phone.NUMBER + ") >= 8", null, sortOrder);我得到无效的列 DISTINCT display_name
            • 让我们尝试在“DISTINCT”->“DISTINCT”处添加一个空格;在这个博客javment.blogspot.com/2011/07/…我做了一个简单的教程,可能对你有帮助。
            • @javment 它只适用于单列,如果您必须查询多列,它的愚蠢解决方案
            • 具有 distinct 的列必须在投影数组的起始处。您还必须指定选择“some_column IS NOT NULL) GROUP BY (distinct_column_name”。来源:qaru.site/questions/2903561/…
            猜你喜欢
            • 1970-01-01
            • 2013-12-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多