ベースのクエリを追加DISTINCT
および/または追加する正しい方法は何でしょうか?GROUPBY
ContentResolver
今のところ、特別な場合ごとにカスタムURIを作成する必要があります。
もっと良い方法はありますか?
(私はまだ最小公分母として1.5をプログラムしています)
ベースのクエリを追加DISTINCT
および/または追加する正しい方法は何でしょうか?GROUPBY
ContentResolver
今のところ、特別な場合ごとにカスタムURIを作成する必要があります。
もっと良い方法はありますか?
(私はまだ最小公分母として1.5をプログラムしています)
contentResolverにクエリを実行するときに、次のコマンドを使用して、すばらしいハックを行うことができます。
String selection = Models.SOMETHING + "=" + something + ") GROUP BY (" + Models.TYPE;
SELECTで複数の列を指定してDISTINCTを使用する場合は、GROUPBYを使用する必要があります。
これを使用するためのContentResolver.queryのミニハック:
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());
}
このコードは、デバイスの受信トレイから送信者ごとに最後のSMSを1つ選択します。
注:GROUP BYの前に、常に少なくとも1つの条件を記述する必要があります。ContentResolver.queryメソッド内の結果のSQLクエリ文字列は次のようになります。
SELECT DISTINCT address, body FROM sms WHERE (type=1) AND (address IS NOT NULL) GROUP BY (address)
誰も答えに来なかったので、私はこれをどのように解決したかを説明します。基本的に、ケースごとにカスタム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);
オーバーライドさContentProvider
れたクエリメソッドには、distinctを使用するための特定のURIマッピングがあります。
次に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;
}
Group Byは使用していませんが、コンテンツリゾルバークエリでDistinctを使用しています。
Cursor cursor = contentResolver
.query(YOUR_URI,
new String[] {"Distinct "+ YOUR_COLUMN_NAME},
null,
null, null);
射影にDistinctキーワードを追加することも私にとってはうまくいきましたが、distinctキーワードが最初の引数である場合にのみ機能しました。
String[] projection = new String[]{"DISTINCT " + DBConstants.COLUMN_UUID, ... };
条件によっては、「distinct(COLUMN_NAME)」を選択として使用でき、完全に機能します。ただし、条件によっては例外が発生します。
例外が発生した場合は、HashSetを使用して列の値を格納します。
// 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));
投影に複数の列がある場合は、次のようにする必要があります。
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は小さなハックですが、完全に正常に機能します
groupbyとdistinctを使用するためのユーティリティメソッドを作成しました。
thread_id
これは、MMSデータベースから最後のメッセージ日付で未表示を選択する例です。
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
}
明確な値を取得する方が簡単かもしれませんが、プロジェクションテーブルの列名の前にDISTINCT単語を追加してみてください
String[] projection = new String[]{
BaseColumns._ID,
"DISTINCT "+ Mediastore.anything.you.want
};
そしてそれをコンテンツリゾルバーのクエリメソッドへの引数として使用してください!
私はあなたを助けたいと思っています、なぜなら私は数日前に同じ質問をするからです