18

かなり興味深い状況があります。アドレスとメッセージでいっぱいの 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本当にわかりません。私は PHP で MySQL をよく使用してきましたが、これまで触れる必要はありませんでしたHAVINGHAVING句をに設定しようと"MAX(date)"しましたが、効果がありませんでした。GROUP BY句をに設定すると"address, date"、それらは日付でソートされますが、もちろん、グループ化されているのではなく、すべて個別です (日付が異なるため)。

Google 検索は役に立たないことが判明しました。「 android sqlite order before group」や「android sqlite group by order 」などのクエリでは、関連する結果は得られません。

句を削除せずに (これに依存しているため) 、アドレスごとに最新のメッセージを 1 つ選択するにはどうすればよいですか? 2 つのクエリが必要ですか?GROUPCOUNT()

編集: @Adrianがコメントで私にリンクした回答に基づいて、同じ結果を生成する2つのクエリを思いつきました。カウントが 7 (アドレスごとのメッセージではなく、アドレスの総数) であり、表示されたアドレスは最新のメッセージのアドレスではありませんでした。

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
);
4

2 に答える 2

16

問題をはるかに簡単にする拡張機能があり
ます。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
于 2012-09-26T18:56:33.553 に答える
7

解決しました!最終的に@CLの組み合わせを使用しました。の方法と、編集した投稿で概説した方法 ( @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
);

そして、それは完璧に機能しています!

于 2012-09-26T19:27:10.670 に答える