Select table 每个ID的最新3条记录
Select the latest 3 records for each ID in a table
我有一个带有复合主键(ID
、Date
)的 table,如下所示。
+------+------------+-------+
| ID | Date | Value |
+------+------------+-------+
| 1 | 1433419200 | 15 |
| 1 | 1433332800 | 23 |
| 1 | 1433246400 | 41 |
| 1 | 1433160000 | 55 |
| 1 | 1432900800 | 24 |
| 2 | 1433419200 | 52 |
| 2 | 1433332800 | 23 |
| 2 | 1433246400 | 39 |
| 2 | 1433160000 | 22 |
| 3 | 1433419200 | 11 |
| 3 | 1433246400 | 58 |
| ... | ... | ... |
+------+------------+-------+
Date
列上还有一个单独的索引。 table 大小适中,目前约 600k 行并且每天增长约 2k。
我想做一个 SELECT 查询 returns 每个 ID
的最新 3 条记录(按 Date
时间戳排序)。对于每个给定的 ID
,Date
值始终是唯一的,因此无需担心此处 Date
的关系。
我尝试了一种自连接方法,受到 this answer 的启发,但是 运行 花了好几秒钟,但什么也没返回:
SELECT p1.ID, p1.Date, p1.Value FROM MyTable AS p1
LEFT JOIN MyTable AS p2
ON p1.ID=p2.ID AND p1.Date<=p2.Date
GROUP BY p1.ID
HAVING COUNT(*)<=5
ORDER BY p1.ID, p1.Date DESC;
什么是快速解决方案?
首先,下面是不等式方法的正确查询:
SELECT p1.ID, p1.Date, p1.Value
FROM MyTable p1 LEFT JOIN
MyTable AS p2
ON p1.ID = p2.ID AND p2.Date <= p1.Date
--------------------------^ fixed this condition
GROUP BY p1.ID, p1.Date, p1.Value
HAVING COUNT(*) <= 5
ORDER BY p1.ID, p1.Date DESC;
我不确定在 SQLite 中是否有快速的方法来执行此操作。在大多数其他数据库中,您可以使用 ANSI 标准 row_number()
函数。在MySQL中,可以使用变量。这些在 SQLite 中都是困难的。您最好的解决方案可能是使用游标。
以上可以受益于 MyTable(Id, Date)
上的索引。
您可以为每个 ID 查找最近的三个日期:
SELECT ID, Date, Value
FROM MyTable
WHERE Date IN (SELECT Date
FROM MyTable AS T2
WHERE T2.ID = MyTable.ID
ORDER BY Date DESC
LIMIT 3)
或者,查找每个 ID 的第三个最近日期,并将其用作限制:
SELECT ID, Date, Value
FROM MyTable
WHERE Date >= IFNULL((SELECT Date
FROM MyTable AS T2
WHERE T2.ID = MyTable.ID
ORDER BY Date DESC
LIMIT 1 OFFSET 2),
0)
两个查询都应该从主键的索引中获得良好的性能。
SELECT distinct x.ID,x.Date,X.Value
FROM ( SELECT DISTINCT ID FROM XXXTable ) c
CROSS APPLY (
select top 3 A.ID,a.Date,Value,[Count] from (
SELECT distinct ID,Date,Value, ROW_NUMBER()
over (
PARTITION BY ID
order by Date
) AS [Count] where c.ID = t.ID
) A order by [Count] desc
我有一个带有复合主键(ID
、Date
)的 table,如下所示。
+------+------------+-------+ | ID | Date | Value | +------+------------+-------+ | 1 | 1433419200 | 15 | | 1 | 1433332800 | 23 | | 1 | 1433246400 | 41 | | 1 | 1433160000 | 55 | | 1 | 1432900800 | 24 | | 2 | 1433419200 | 52 | | 2 | 1433332800 | 23 | | 2 | 1433246400 | 39 | | 2 | 1433160000 | 22 | | 3 | 1433419200 | 11 | | 3 | 1433246400 | 58 | | ... | ... | ... | +------+------------+-------+
Date
列上还有一个单独的索引。 table 大小适中,目前约 600k 行并且每天增长约 2k。
我想做一个 SELECT 查询 returns 每个 ID
的最新 3 条记录(按 Date
时间戳排序)。对于每个给定的 ID
,Date
值始终是唯一的,因此无需担心此处 Date
的关系。
我尝试了一种自连接方法,受到 this answer 的启发,但是 运行 花了好几秒钟,但什么也没返回:
SELECT p1.ID, p1.Date, p1.Value FROM MyTable AS p1
LEFT JOIN MyTable AS p2
ON p1.ID=p2.ID AND p1.Date<=p2.Date
GROUP BY p1.ID
HAVING COUNT(*)<=5
ORDER BY p1.ID, p1.Date DESC;
什么是快速解决方案?
首先,下面是不等式方法的正确查询:
SELECT p1.ID, p1.Date, p1.Value
FROM MyTable p1 LEFT JOIN
MyTable AS p2
ON p1.ID = p2.ID AND p2.Date <= p1.Date
--------------------------^ fixed this condition
GROUP BY p1.ID, p1.Date, p1.Value
HAVING COUNT(*) <= 5
ORDER BY p1.ID, p1.Date DESC;
我不确定在 SQLite 中是否有快速的方法来执行此操作。在大多数其他数据库中,您可以使用 ANSI 标准 row_number()
函数。在MySQL中,可以使用变量。这些在 SQLite 中都是困难的。您最好的解决方案可能是使用游标。
以上可以受益于 MyTable(Id, Date)
上的索引。
您可以为每个 ID 查找最近的三个日期:
SELECT ID, Date, Value
FROM MyTable
WHERE Date IN (SELECT Date
FROM MyTable AS T2
WHERE T2.ID = MyTable.ID
ORDER BY Date DESC
LIMIT 3)
或者,查找每个 ID 的第三个最近日期,并将其用作限制:
SELECT ID, Date, Value
FROM MyTable
WHERE Date >= IFNULL((SELECT Date
FROM MyTable AS T2
WHERE T2.ID = MyTable.ID
ORDER BY Date DESC
LIMIT 1 OFFSET 2),
0)
两个查询都应该从主键的索引中获得良好的性能。
SELECT distinct x.ID,x.Date,X.Value
FROM ( SELECT DISTINCT ID FROM XXXTable ) c
CROSS APPLY (
select top 3 A.ID,a.Date,Value,[Count] from (
SELECT distinct ID,Date,Value, ROW_NUMBER()
over (
PARTITION BY ID
order by Date
) AS [Count] where c.ID = t.ID
) A order by [Count] desc