没有游标的sql行差异

时间:2014-09-18 11:54:04

标签: sql

我试图在行之间获得日期差距(以天为单位)。 例如,我的数据按saleDate排序,如下所示:

ID  | saleDate                    ID  | gapInDays
10  | 1/1/2014                    10  | 4             -- (5/1/2014 -  1/1/2014).Days
20  | 5/1/2014                    20  | 2  
30  | 7/1/2014      ====>>>       30  | 3
40  | 10/1/2014                   40  | 7
50  | 17/1/2014                   50  | 1             --  last row will always be 1

在代码中执行它并不是什么大问题,但因为行数很大(几百万)我试图在SP级别这样做。我假设我可以使用光标,但我知道它很慢。

任何解决方案都将受到高度赞赏。

皮尼。

4 个答案:

答案 0 :(得分:2)

如果您使用的是SQL SERVER 2012 / Oracle / Postgres / DB2,则可以使用LEAD(),LAG()函数。

select ID,saleDate,LEAD(saleDate) over (order by saleDate) DateOfNextRow
    ,Isnull(Datediff(dd,saleDate,LEAD(saleDate) over (order by saleDate)),1) as gapInDays
from Order

对于SQL SERVER 2005/2008,您可以使用ROW_NUMBER()等窗口函数。

答案 1 :(得分:1)

<德尔> 如果您使用的是MS SQL Server 2012(或支持相同或类似功能的其他数据库),则可以使用LAG()函数访问以前的行(或LEAD()以访问后续行)

显然,您希望这可以在缺少LAGLEAD窗口函数的SQL Azure上运行。

应该使用的一个解决方案是使用在日期列上应用的ROW_NUMBER排名函数。 Azure支持ROW_NUMBER,因此此代码应该有效:

select t1.id, isnull(datediff(day, t1.saledate, t2.saledate), 1) as gapInDays 
from 
(select id, saledate, rn = row_number() over (order by saledate, id) from gaps) t1
left join 
(select id, saledate, rn = row_number() over (order by saledate, id) from gaps) t2
on t1.rn = t2.rn-1

如果你想要它稍微更紧凑(如果Azure支持我相信它的ctes)你可以将它作为一个公用表表达式来执行:

;with c as (
    select id, saledate, r = row_number() over (order by saledate, id) from gaps
)

select c.id, isnull(datediff(day, c.saledate, c2.saledate), 1) as gapInDays 
from c left join c c2 on c.r = c2.rn-1

在这些查询中,我按saledate对行进行了排序,如果不正确,则可能需要将其更改为order by id, saledate,如果它是确定顺序的ID。

答案 2 :(得分:0)

如果您的ID是严格顺序的,您可以执行类似的操作

select 
    a.id, b.saleDate - a.saleDate 
from 
    yourTable as a, yourTable as b 
where 
    a.id = b.id-1

答案 3 :(得分:0)

如果数据库是SQL Server,那么以下查询应该有效。

WITH Sales AS
(
    SELECT
        *, ROW_NUMBER() OVER (ORDER BY SaleDate) AS RowNumber
    FROM
        TableName
)
SELECT
    DATEDIFF(DAY, T1.SaleDate, T2.SaleDate)
FROM
    Sales AS T1 INNER JOIN Sales AS T2
    ON  T1.RowNumber = T2.RowNumber - 1;
相关问题