我有一个包含许多ID的表,每个ID都有许多日期,甚至还有一些没有日期的ID。对于每个ID和日期组合,我想选择ID,日期和与该相同ID相关联的下一个最大日期,如果不存在则为null。
样本表:
ID Date
1 5/1/10
1 6/1/10
1 7/1/10
2 6/15/10
3 8/15/10
3 8/15/10
4 4/1/10
4 4/15/10
4
期望的输出:
ID Date Next_Date
1 5/1/10 6/1/10
1 6/1/10 7/1/10
1 7/1/10
2 6/15/10
3 8/15/10
3 8/15/10
4 4/1/10 4/15/10
4 4/15/10
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
AND mytable.id = mytablemin.id
) AS NextDate
FROM mytable
这已在SQL Server 2008 R2上测试过(但它应该适用于其他DBMS)并产生以下输出:
id日期NextDate
----------- ----------------------- ---------------- -------
1 2010-05-01 00:00:00.000 2010-06-01 00:00:00.000
1 2010-06-01 00:00:00.000 2010-06-15 00:00:00.000
1 2010-07-01 00:00:00.000 2010-08-15 00:00:00.000
2 2010-06-15 00:00:00.000 2010-07-01 00:00:00.000
3 2010-08-15 00:00:00.000 NULL
3 2010-08-15 00:00:00.000 NULL
4 2010-04-01 00:00:00.000 2010-04-15 00:00:00.000
4 2010-04-15 00:00:00.000 2010-05-01 00:00:00.000
4 NULL NULL
更新1:
对于那些感兴趣的人,我比较了SQL Server 2008 R2中两个变体的性能(一个使用MIN聚合,另一个使用TOP 1和ORDER BY):
如果日期列没有索引,MIN版本的成本为0.0187916,TOP / ORDER BY版本的成本为0.115073,因此MIN版本“更好”。
使用日期列上的索引,它们执行相同的操作。
请注意,这仅仅测试了这9条记录,因此结果可能(非常)虚假......
更新2:
结果适用于10,000个均匀分布的随机记录。 TOP / ORDER BY查询需要很长时间才能运行100,000条记录我不得不取消它并放弃。
如果你的数据库是oracle,你可以使用 lead() and lag()
功能。
SELECT id, date,
LEAD(date, 1, 0) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE,
FROM Your_table
ORDER BY ID;
SELECT
id,
date,
( SELECT date
FROM table t1
WHERE t1.date > t2.date
ORDER BY t1.date LIMIT 1 )
FROM table t2