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)
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);
Vous pouvez faire un joli piratage lorsque vous interrogez contentResolver, utilisez:
String selection = Models.SOMETHING + "=" + something + ") GROUP BY (" + Models.TYPE;
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)
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;
}
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);
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, ... };
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 ....
// 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));