日期范围的简单SQL查询

时间:2015-09-28 22:52:43

标签: sql sql-server sql-server-2008

我需要一种方法来查找每组相同ID设置的天数。例如,如果有两行ID1,第一个日期是第一个,第二个日期是第4个,第一个的计算将是9月4日 - 9月1日(因为第4个是ID1的下一个日期)和第四个的计算是今天(9月28日) - 9月4日(因为第4个是ID1的最后一个日期,ID1的第4个日期之后没有日期)。我在下面的旁边列出了计算每列的公式。

IDs    Date          
ID1    09/01/2015    
ID1    09/04/2015  
ID2    09/04/2015    
ID2    09/09/2015   
ID2    09/15/2015  
ID3    09/09/2015 
ID4    09/15/2015   

IDs    Date           Days      Formula...
ID1    09/01/2015     3         Sept 4th - Sept 1st
ID1    09/04/2015     22        Today - Sept 4th
ID2    09/04/2015     5         Sept 9th - Sept 4th
ID2    09/09/2015     6         Sept 15th - Sept 9th  
ID2    09/15/2015     13        Today - Sept 15th
ID3    09/09/2015     19        Today - Sept 9th
ID4    09/15/2015     13        Today - Sept 15th

4 个答案:

答案 0 :(得分:3)

您基本上在寻找lead()功能。并且,你没有它,所以你必须即兴发挥。以下是使用cross apply的方法:

select t.*,
       datediff(day, t.date, coalesce(n.date, getdate())
from table t outer apply
     (select top 1 t2.date
      from table t2
      where t2.id = t.id and t2.date > t.date
      order by t2.date
     ) n;

这应该具有合理的性能,索引在(id, date)

答案 1 :(得分:2)

使用公用表表达式,您可以将表排列成一个临时视图,其中包含每个ID记录的开始日期和结束日期,如下所示:http://sqlfiddle.com/#!3/af078/7

with t1 (id, dt, ndx) as (
  select id, dt, row_number() over (partition by id order by dt)
  from id_dates
)
,
t2 (id, startdt, enddt) as (
  select t1.id, t1.dt, coalesce(t2.dt, convert(date, getdate()))
  from t1
  left join t1 t2
  on t2.id = t1.id
  and t2.ndx = t1.ndx + 1
)
select * from t2

确保使用coalesce函数获取最后一行的当前日期(否则它将从左连接中为空)。

从那里开始,使用datediff()函数很简单:http://sqlfiddle.com/#!3/af078/8

with t1 (id, dt, ndx) as (
  select id, dt, row_number() over (partition by id order by dt)
  from id_dates
)
,
t2 (id, startdt, enddt) as (
  select t1.id, t1.dt, coalesce(t2.dt, convert(date, getdate()))
  from t1
  left join t1 t2
  on t2.id = t1.id
  and t2.ndx = t1.ndx + 1
)
select id, startdt, datediff(day, startdt, enddt) as dtcount
from t2

答案 2 :(得分:1)

您可以使用ROW_NUMBERLEFT JOIN一起执行此操作:

SQL Fiddle

WITH Cte AS(
    SELECT *, 
    rn = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Date])
    FROM tbl
)
SELECT
    t1.*,
    Days = DATEDIFF(DAY, t1.Date, ISNULL(t2.Date, GETDATE()))
FROM Cte t1
LEFT JOIN Cte t2
    ON t1.ID = t2.ID
    AND t1.rn  = t2.rn - 1

答案 3 :(得分:1)

这是一个工作示例,您可以在没有任何连接的情况下执行此操作。 只需使用Lead窗口功能。

--Here is your data
DECLARE @Data TABLE(ID NVARCHAR(8),Date DATE)
INSERT INTO @Data(ID,Date)
VALUES
('ID1','09/01/2015'),
('ID1','09/04/2015'),
('ID2','09/04/2015'),   
('ID2','09/09/2015'), 
('ID2','09/15/2015'),
('ID3','09/09/2015'),
('ID4','09/15/2015')

--This is all you need, Assuming your using a version of SQL that supports LEAD!!!
SELECT  ID,DATEDIFF(D,Date,ISNULL(LEAD(Date) OVER(PARTITION BY ID ORDER BY Date),GETDATE()))
FROM        @Data