如何在具有连续日期和重复数据的记录中查找日期范围

时间:2010-05-15 07:03:56

标签: sql-server database tsql sql-server-2000

对此可能有任何简单的解决方案,但我看不到它。我有一个连续日期的表格,并经常复制这几个连续日期的相关数据:

Date       Col1  Col2
5/13/2010  1     A
5/14/2010  1     A
5/15/2010  2     B
5/16/2010  1     A
5/17/2010  1     A
5/18/2010  3     C
5/19/2010  3     C
5/20/2010  3     C

使用MS T-SQL,我希望找到每次运行不同Col1和Col2值的开始和结束日期:

StartDate  EndDate    Col1  Col2
5/13/2010  5/14/2010  1     A
5/15/2010  5/15/2010  2     B
5/16/2010  5/17/2010  1     A
5/18/2010  5/20/2010  3     C

假设:从来没有任何错过的日期。 Col1和Col2不为空。 任何想法 - 最好不使用游标? 非常感谢, -alan

2 个答案:

答案 0 :(得分:3)

对于SQL 2005+,我认为以下内容应该有效

WITH DATES AS
(
   SELECT COL1, COL2, DATE,
      DATEADD(DAY, -1 * ROW_NUMBER() 
      OVER(PARTITION BY COL1, COL2 ORDER BY DATE), DATE) AS GRP
   FROM YOUR_TABLE
)
SELECT COL1, COL2, MIN(DATE) AS STARTDATE, MAX(DATE) AS ENDDATE
FROM DATES
GROUP BY COL1, COL2, GRP

如果您有任何重复记录,请使用DENSE_RANK()代替ROW_NUMBER()

对于SQL 2000,有一个子查询和一个涉及的联合查询。

SELECT COL1, COL2, MIN(DATE) AS STARTDATE, MAX(DATE) AS ENDDATE
FROM (SELECT COL1, COL2, DATE,
    (SELECT MIN(DATE)
     FROM YOUR_TABLE B
     WHERE B.DATE >= A.DATE AND B.COL1 = A.COL1 AND B.COL2 = A.COL2
           AND NOT EXISTS
           (SELECT *
            FROM YOUR_TABLE C
            WHERE C.COL1 = B.COL1 AND C.COL2 = B.COL2
            AND DATEDIFF(DAY, B.DATE, C.DATE) = 1)
    ) AS GRP
    FROM YOUR_TABLE A
)
GROUP BY COL1, COL2, GRP

答案 1 :(得分:1)

以下是使用outer apply的一种方法。将@t替换为您的表名。

SELECT    head.date, last.date, head.col1, head.col2
FROM      @t head
OUTER APPLY (
          SELECT TOP 1 *
          FROM @t t
          WHERE t.date < head.date
          ORDER BY t.date desc
          ) prev
OUTER APPLY (
          SELECT TOP 1 *
          FROM @t t
          WHERE t.date > head.date
          AND (t.col1 <> head.col1 or t.col2 <> head.col2)
          ORDER BY t.date
          ) next
OUTER APPLY (
          SELECT TOP 1 *
          FROM @t t
          WHERE (t.date < next.date or next.date is null)
          AND (t.col1 = head.col1 and t.col2 = head.col2)
          ORDER BY t.date
          ) last
WHERE (prev.col1 is null or head.col1 <> prev.col1 or head.col2 <> prev.col2)

查询首先选择“head”行:开始新col1, col2组的行。这是通过查找“prev”ious行来完成的,并且说它在where子句中必须是不同的。

然后它搜索col1, col2组的结尾。这是一个两步过程:首先搜索“下一个”组的第一行,然后搜索“最后”行之前的行。

Date       Col1  Col2
...
5/15/2010  2     B      <-- "prev" row
5/16/2010  1     A      <-- "head" row
5/17/2010  1     A      <-- "last" row
5/18/2010  3     C      <-- "next" row
...

查询结果与您问题中的示例输出相匹配。