次の列を含むデータベーステーブルがあります。
id code value datetime timestamp
このテーブルでは、一意の値のみがID、つまり主キーに存在します。
日時値に基づいて、このテーブル内の最後の個別のレコードセットを取得したい。たとえば、以下が私のテーブルだとしましょう
id code value datetime timestamp
1 1023 23.56 2011-04-05 14:54:52 1234223421
2 1024 23.56 2011-04-05 14:55:52 1234223423
3 1025 23.56 2011-04-05 14:56:52 1234223424
4 1023 23.56 2011-04-05 14:57:52 1234223425
5 1025 23.56 2011-04-05 14:58:52 1234223426
6 1025 23.56 2011-04-05 14:59:52 1234223427
7 1024 23.56 2011-04-05 15:00:12 1234223428
8 1026 23.56 2011-04-05 15:01:14 1234223429
9 1025 23.56 2011-04-05 15:02:22 1234223430
ID 4、7、8、および9のレコード、つまり(datetime値に基づく)異なるコードを持つレコードの最後のセットを取得したい。このテーブルには最終的に何百万ものレコードと何百もの個々のコード値が含まれるので、私が強調したのは、私が達成しようとしているものの単なる例です。
これを達成するためにどのSQLステートメントを使用できますか?単一のSQLステートメントでそれを達成することはできません。私のデータベースはMySQL 5です。
これはあなたのために働くはずです。
SELECT *
FROM [tableName]
WHERE id IN (SELECT MAX(id) FROM [tableName] GROUP BY code)
IdがAUTO_INCREMENTの場合、最新の日時も最高のidを持つため、計算がはるかに高価な日時を心配する必要はありません。
更新:パフォーマンスの観点から、多数のレコードを処理する場合は、id
列とcode
列にインデックスが付けられていることを確認してください。 id
が主キーの場合、これは組み込まれていますが、code
およびid
をカバーする非クラスター化インデックスを追加する必要がある場合があります。
これを試して:
SELECT *
FROM <YOUR_TABLE>
WHERE (code, datetime, timestamp) IN
(
SELECT code, MAX(datetime), MAX(timestamp)
FROM <YOUR_TABLE>
GROUP BY code
)
それは古い投稿ですが、大きなテーブルで@smdragerの回答をテストするのは非常に遅かったです。これに対する私の修正は、「where in」の代わりに「inner join」を使用することでした。
SELECT *
FROM [tableName] as t1
INNER JOIN (SELECT MAX(id) as id FROM [tableName] GROUP BY code) as t2
ON t1.id = t2.id
これは本当に速く働きました。
私はこのようなことを試してみます:
select * from table
where id in (
select id
from table
group by code
having datetime = max(datetime)
)
(免責事項:これはテストされていません)
Datetimeが大きい行のidも大きい場合、smdragerによって提案されたソリューションはより高速です。
既存のすべての回答が_GROUP BY code
テーブル全体。論理的に正しい場合、実際にはこのクエリはテーブル全体(!)を通過します(確認するにはEXPLAIN
を使用します)。私の場合、テーブルには50万行未満の行があり、...GROUP BY code
0.3秒かかりますが、これは絶対に許容できません。
ただし、ここで自分のデータの知識を使用できます(「投稿の最後のコメントを表示」と読みます)。
code
の量>>取得する「トップ」レコードの量数値を試してみたところ、最後の50レコードだけを選択すると、常に20種類のcode
を見つけることができることがわかりました。この場合、次のクエリが機能します(id
の代わりにdatetime
を使用する可能性が高いことについて@smdragerのコメントに留意してください)
SELECT id, code
FROM tablename
ORDER BY id DESC
LIMIT 50
テーブル全体をチェックする必要がないため、最後の50エントリのみを選択するのは非常に簡単です。そして残りは、それらの50個のエントリから異なるcode
を持つtop-20を選択することです。
明らかに、50(100、500)要素のセットに対するクエリは、数十万のエントリがあるテーブル全体に対するクエリよりもかなり高速です。
Raw SQL "後処理"
SELECT MAX(id) as id, code FROM
(SELECT id, code
FROM tablename
ORDER BY id DESC
LIMIT 50) AS nested
GROUP BY code
ORDER BY id DESC
LIMIT 20
これにより、id
のリストが非常に速くなり、追加のJOINを実行する場合は、このクエリをさらに別のネストされたクエリとして配置し、すべての結合を実行します。
バックエンド側の「後処理」
その後、プログラミング言語でデータを処理し、code
が別個のレコードのみを最終セットに含める必要があります。
ある種のPython擬似コード:
records = select_simple_top_records(50)
added_codes = []
top_records = []
for record in records:
# If record for this code was already found before
# Note: this is not optimal, better to use structure allowing O(1) search and insert
if record['code'] in added_codes:
continue
# Save record
top_records.append(record)
added_codes.append(record['code'])
# If we found all top-20 required, finish
if len(top_records) >= 20:
break