Android: Distintivo y GroupBy en ContentResolver
distinct group-by (9)
¿Cuál sería una forma sensata de agregar DISTINCT
y GROUPBY
a las consultas basadas en ContentResolver
? En este momento tengo que crear un URI personalizado para cada caso especial. ¿Hay una mejor manera? (Todavía programo 1.5 como el mínimo común denominador)
Aunque no he usado Group By , he usado Distinct en la consulta de resolución de contenido.
Cursor cursor = contentResolver .query(YOUR_URI, new String[] {"Distinct "+ YOUR_COLUMN_NAME}, null, null, null);
Como nadie vino a responder, voy a contar cómo resolví esto. Básicamente crearía un URI personalizado para cada caso y pasaría los criterios en el parámetro de selection
. Luego, dentro de ContentProvider#query
, identificaría el caso y construiría una consulta sin formato según el nombre de la tabla y el parámetro de selección.
Aquí está el ejemplo rápido:
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);
En algunas condiciones, podemos usar "distinto (COLUMN_NAME)" como la selección, y funciona perfectamente. pero en alguna condición, causará una excepción.
cuando causa una excepción, usaré un HashSet para almacenar los valores de la columna ...
En su método de consulta de ContentProvider
invalidado, tenga una asignación de URI específica para usar distintas.
Luego use SQLiteQueryBuilder
y llame al 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;
}
Puedes hacer un buen truco cuando consultes contentResolver, usa:
String selection = Models.SOMETHING + "=" + something + ") GROUP BY (" + Models.TYPE;
Quizás sea más simple obtener valores distintos, intente agregar la palabra DISTINCT antes del nombre de la columna que desea en la tabla de proyección
String[] projection = new String[]{
BaseColumns._ID,
"DISTINCT "+ Mediastore.anything.you.want
};
y úselo como argumento para consultar el método de resolución de contenido.
Espero ayudarte, porque tengo la misma pregunta antes de algunos días
Si desea usar DISTINCT con SELECT más de una columna, debe usar GROUP BY.
Mini Hack sobre ContentResolver.query para usar esto:
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());
}
Este código selecciona un último sms para cada uno de los remitentes de la bandeja de entrada del dispositivo.
Nota: antes de GROUP BY siempre necesitamos escribir al menos una condición. El resultado de la cadena de consulta SQL dentro del método ContentResolver.query:
SELECT DISTINCT address, body FROM sms WHERE (type=1) AND (address IS NOT NULL) GROUP BY (address)
También me fue útil agregar la palabra clave Distinct en la proyección, sin embargo, solo funcionó cuando la palabra clave distinct fue el primer argumento:
String[] projection = new String[]{"DISTINCT " + DBConstants.COLUMN_UUID, ... };
// 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));