web-dev-qa-db-fra.com

Android: Distinct et GroupBy dans ContentResolver

Quelle serait la bonne façon d'ajouter des requêtes basées sur DISTINCT et/ou GROUPBY à ContentResolver?

Pour le moment, je dois créer un URI personnalisé pour chaque cas spécial.

Y a-t-il une meilleure façon?

(Je programme toujours pour 1,5 comme le plus petit dénominateur commun)

31
Bostone

Puisque personne n'est venu répondre, je vais juste dire comment j'ai résolu cela. Fondamentalement, je créerais un URI personnalisé pour chaque cas et passerais les critères dans le paramètre selection. Puis à l'intérieur ContentProvider#query Je voudrais identifier le cas et construire une requête brute basée sur le nom de la table et le paramètre de sélection.

Voici un exemple rapide:

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);
14
Bostone

Vous pouvez faire un joli piratage lorsque vous interrogez contentResolver, utilisez:

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

Si vous souhaitez utiliser DISTINCT avec SELECT plus d'une colonne, vous devez utiliser GROUP BY.
Mini Hack sur ContentResolver.query pour utiliser ceci:

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());
        }

Ce code sélectionne un dernier sms pour chacun des expéditeurs dans la boîte de réception de l'appareil.
Remarque: avant GROUP BY, nous devons toujours écrire au moins une condition. La chaîne de requête SQL de résultat dans la méthode ContentResolver.query:

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

Dans votre méthode de requête ContentProvider substituée, utilisez un mappage d'URI spécifique pour utiliser distinct.

Utilisez ensuite SQLiteQueryBuilder et appelez la méthode 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;
}
13
Brady Kroupa

Bien que je n'aie pas utilisé Group By, j'ai utilisé Distinct dans la requête de résolution de contenu.

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

6
W00di

L'ajout du mot clé Distinct dans la projection a également fonctionné pour moi, mais cela n'a fonctionné que lorsque le mot clé distinct était le premier argument:

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

Dans certaines conditions, nous pouvons utiliser "distinct (COLUMN_NAME)" comme sélection, et cela fonctionne parfaitement. mais dans certaines conditions, cela provoquera une exception.

quand il provoque une exception, j'utilise un HashSet pour stocker les valeurs de la colonne ....

0
Mikonos
// 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));
0
Khizhny Andrey