なかなか面白い状況です。 SQLiteデータベースにアドレスとメッセージがいっぱいあります(アドレスは一意ではなく、メッセージは一意です)。各メッセージには、日付も関連付けられています。 最初のメッセージのアドレス、メッセージ、日付、およびアドレスに関連付けられているメッセージの数を選択します。
したがって、「アドレスごとにグループ化して、アドレスごとに1つのメッセージのみを取得し、日付順に並べ替え、アドレス列のCOUNTをフェッチすることもできる」と考えました。
私はそれをしました、そしてそれはうまくいきます...ちょっと。正しい数を取得し、アドレスごとに1つのメッセージのみを取得し、日付順に並べ替えますが、アドレスの最新メッセージは選択しません。それは恣意的であるように見えます。
例として、アドレスYからの3つのメッセージ(最も古いものから最新のものまで)A、B、C、およびアドレスZからの3つのメッセージD、E、Fがあります。クエリはメッセージBおよびEをフェッチします次に日付順に並べ替えます。メッセージCとFをフェッチする必要があります。日付順にソートします。
ここに私がこれまでに持っているものがあります:
_// Expanded version:
Cursor cursor = db.query(
/* FROM */ "messages_database",
/* SELECT */ new String[]{ "*", "COUNT(address) AS count" },
/* WHERE */ null,
/* WHERE args */ null,
/* GROUP BY */ "address",
/* HAVING */ null,
/* ORDER BY */ "date DESC"
);
// Or, same code on one line:
Cursor cursor = db.query("messages_database", new String[]{ "*", "COUNT(address) AS count" }, null, null, "address", null, "date DESC");
_
これはHAVING
句と関係があるように思えますが、本当にわかりません。私はMySQLをPHPで頻繁に使用しましたが、これまでHAVING
に触れる必要はありませんでした。 HAVING
句を"MAX(date)"
に設定しようとしましたが、効果がありませんでした。 _GROUP BY
_句を_"address, date"
_に設定すると、日付順に並べ替えられますが、もちろん日付は異なるため、グループ化されているのではなく、すべて個別です。
グーグル検索は実を結ばなかった。 「Android sqlite order before group」や「Android sqlite group by order」のようなクエリでは、関連する結果は得られません。
GROUP
句を削除せずに、各アドレスに対してone latestメッセージを選択するにはどうすればよいですか(COUNT()
がこれに依存しているため)? 2つのクエリが必要ですか?
Edit: the answer に基づいて、@ Adrianがコメントにリンクしてくれたので、2つのクエリを作成しました。同じ結果;カウントが7(アドレス(メッセージの数ではなくアドレスの総数)/アドレス)である1行で、表示されたアドレスは最新のメッセージのアドレスではありませんでした。
2つのクエリは次のとおりです。
_Cursor cursor = db.rawQuery(
"SELECT t.*, COUNT(t.message_content) AS count "
+ "FROM messages_database t "
+ "INNER JOIN ("
+ " SELECT address, MAX(date) AS maxdate "
+ " FROM messages_database "
+ " GROUP BY address "
+ ") ss ON t.address = ss.address AND t.date = ss.maxdate",
null
);
Cursor cursor = db.rawQuery(
"SELECT t1.*, COUNT(t1.message_content) AS count "
+ "FROM messages_database t1 "
+ "LEFT OUTER JOIN messages_database t2 "
+ "ON (t1.address = t2.address AND t1.date < t2.date) "
+ "WHERE t2.address IS NULL",
null
);
_
SQLiteには greatest-n-per-group 問題をはるかに容易にする拡張機能があります。MAX()
またはMIN()
集約関数を使用していて、集約関数で使用したりグループ化したりせずに、同時に他の列を選択する場合は、これらの列の結果の値は、最大値/最小値を持つ同じレコードから取得されることが保証されています。 (これは他のSQL方言では許可されておらず、 SQLite 3.7.11 で導入されました。)
したがって、問題については、次のようなクエリを使用できます。
SELECT *, COUNT(address) AS count, MAX(date)
FROM messages_database
GROUP BY address
SQLite 3.7.11(ほとんどのAndroidバージョン)にある可能性が高い)または別のSQLエンジンを使用していない場合、次のクエリが機能します。
SELECT *,
(SELECT COUNT(address) AS count
FROM messages_database m2
WHERE m1.address = m2.address)
FROM messages_database m1
WHERE date = (SELECT MAX(date)
FROM messages_database m3
WHERE m1.address = m3.address)
GROUP BY address
解決しました!私は最終的に @ CL。 のメソッドと編集した投稿で概説したメソッド( this answer で明確化された @ Adrian )。
3つのSELECT
ステートメントを(@CL。の回答で説明したように)使用したくなかったため、彼の方法論を維持しながら、他のステートメントと同じINNER JOIN
の概念を使用しました。
結果はこれです:
Cursor cursor = db.rawQuery(
"SELECT t.*, ss.count AS count "
+ "FROM messages_database t "
+ "INNER JOIN ("
+ " SELECT address, MAX(date) AS maxdate, COUNT(address) AS count "
+ " FROM messages_database "
+ " GROUP BY address "
+ ") ss ON t.address = ss.address AND t.date = ss.maxdate "
+ "GROUP BY t.address "
+ "ORDER BY t.date DESC ",
null
);
そしてそれは完全に働いています!