问题 SQL - 选择下一个日期查询


我有一个包含许多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    

9411
2017-08-31 13:54


起源

你的数据库是什么 - Bharat


答案:


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条记录我不得不取消它并放弃。


14
2017-08-31 14:03



使用排序比使用聚合函数更好。你有一张特别的大桌子 - Андрей Костенко
@Andrii:我不能代表其他数据库,但在SQL Server上它不应该有所作为。如果有一个索引,它就足够聪明地知道它只能读取第一行;如果没有索引,它必须以任何方式扫描整个表。事实上,使用ORDER BY可能会更慢,因为它必须进行O(n * lg(n))排序而不是O(n)扫描。 - Daniel Renshaw
这是一个mssql db,查询通过via访问传递,这意味着LIMIT查询无论如何都无法工作。上面的min查询完全适用于在WHERE语句中添加mytable.id = mytablemin.id的轻微添加。查询有点迟缓,但我现在正在使用的日期字段上没有索引。谢谢大家的帮助。 - John


如果你的数据库是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;

1
2017-08-31 14:02



上面的代码为我产生了一个错误 - 0应该为null,因为oracle sql抱怨它是一个不兼容的数据类型(数字而不是日期),但下面的工作正常:SELECT id,date,LEAD(date,1,null)超过(ID按日期排序,按日期DESC NULLS最后)NEXT_DATE,来自Your_table - bawpie


SELECT id, date, ( SELECT date FROM table t1 WHERE t1.date > t2.date ORDER BY t1.date LIMIT 1 ) FROM table t2


1
2017-08-31 14:01