对此可能有任何简单的解决方案,但我看不到它。我有一个连续日期的表格,并经常复制这几个连续日期的相关数据:
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
答案 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
...
查询结果与您问题中的示例输出相匹配。