Sql 聚合日期范围
我正在努力创建一个查询来汇总一个日期范围,同时按两个字段连续分组-基本上,我正在尝试改变这一点:Sql 聚合日期范围,sql,sql-server-2008,tsql,Sql,Sql Server 2008,Tsql,我正在努力创建一个查询来汇总一个日期范围,同时按两个字段连续分组-基本上,我正在尝试改变这一点: |Key|Valid|DateFrom |DateTo | | 1| 0|2001-01-01|2001-01-31| | 1| 0|2001-02-01|2001-02-20| | 1| 1|2001-02-21|2001-02-28| | 1| 0|2001-03-01|2001-03-15| | 2| 1|2001-01-01|2001-01-3
|Key|Valid|DateFrom |DateTo |
| 1| 0|2001-01-01|2001-01-31|
| 1| 0|2001-02-01|2001-02-20|
| 1| 1|2001-02-21|2001-02-28|
| 1| 0|2001-03-01|2001-03-15|
| 2| 1|2001-01-01|2001-01-31|
| 2| 0|2001-02-01|2001-02-20|
| 2| 0|2001-02-21|2001-02-28|
| 2| 1|2001-03-01|2001-03-15|
为此:
|Key|Valid|DateFrom |DateTo |
| 1| 0|2001-01-01|2001-02-20|
| 1| 1|2001-02-21|2001-02-28|
| 1| 0|2001-03-01|2001-03-15|
| 2| 1|2001-01-01|2001-01-31|
| 2| 0|2001-02-01|2001-02-28|
| 2| 1|2001-03-01|2001-03-15|
当然,一个简单的minDateFrom,MaxDateToGroup by Key,Valid不起作用,因为它不尊重日期范围的时间顺序。应该注意的是,在每个键和有效组内的日期范围中没有间隔
我在这里和网上的其他地方搜索了很多解决方案,找到了很多使用OVER和CTE对日期进行分组的解决方案,但我认为问题是我正在尝试将两个不同的分组考虑在内。我也尝试过将范围转换为单独的日期,但我似乎无法按时间顺序将它们按两组进行汇总
任何帮助都将不胜感激。谢谢。您可以先计算关键行,即有效或关键更改的位置,然后链接到该组的最大日期 编辑-重写以处理DEM标记的角案例。这节经文还涉及序列中的间隙
with keyItems as (
-- First find all the "Key Frames"
select d.*
from
data d
left outer join data d2
on d.[Key]=d2.[key] and d.valid=d2.valid and d.dateFrom = DateAdd(d,1,d2.dateto)
where d2.[key] is null
),
ordered as (
-- This is to provide a sequence number for the main query against these key frames
select
ROW_NUMBER() over (partition by [key] order by datefrom) as row,
*
from keyItems
),
rangeends([key],row,dateto) as (
select o.[key],o.row-1,MAX(d.DateTo)
from ordered o left outer join data d on d.[key]=o.[key] and d.DateTo < o.DateFrom
group by o.[key],o.row-1
union all
select o.[key],MAX(o.row),MAX(d.dateto)
from ordered o inner join data d on d.[key]=o.[key]
group by o.[key]
)
select
o1.[Key],
o1.Valid,
o1.DateFrom,
coalesce(r.dateto,o1.dateTo) as DateTo
from ordered o1
left outer join rangeends r on r.[key]=o1.[Key] and r.row=o1.row
我面前没有SQL客户端,但您可以这样做
WITH
sequenced_data
AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY Key ORDER BY DateFrom) AS KeyRow,
ROW_NUMBER() OVER (PARTITION BY Key, Valid ORDER BY DateFrom) AS KeyValidRow,
*
FROM
yourData
)
SELECT
Key,
Valid,
MIN(DateFrom) AS DateFrom,
MAX(DatTo) AS DateTo
FROM
sequenced_data
GROUP BY
Key,
Valid,
KeyRow - KeyValidRow
ORDER BY
Key,
MIN(DateFrom)
用你的数据进行可视化
|Key|Valid|DateFrom |DateTo |KeyRow|KeyValidRow|KeyRow - KeyValidRow
| 1| 0|2001-01-01|2001-01-31| 1| 1| 0
| 1| 0|2001-02-01|2001-02-20| 2| 2| 0
| 1| 1|2001-02-21|2001-02-28| 3| 1| 2
| 1| 0|2001-03-01|2001-03-15| 4| 3| 1
| 2| 1|2001-01-01|2001-01-31| 1| 1| 0
| 2| 0|2001-02-01|2001-02-20| 2| 1| 1
| 2| 0|2001-02-21|2001-02-28| 3| 2| 1
| 2| 1|2001-03-01|2001-03-15| 4| 2| 2
虽然KeyRow-KeyValidRow不一定告诉您很多,但它确实为每个组提供了一个不同的值,因此对于group BY来说就足够了
无论一个组中有多少条记录,它都能工作,但它确实假设数据中没有间隙或重叠。除了使用光标,我想不出任何东西。但是,这确实有效:
declare @example table (tKey int, Valid int, DateFrom date, DateTo date);
insert into @example values (1, 0, '2001-01-01', '2001-01-31');
insert into @example values (1, 0, '2001-02-01', '2001-02-20');
insert into @example values (1, 1, '2001-02-21', '2001-02-28');
insert into @example values (1, 0, '2001-03-01', '2001-03-15');
insert into @example values (2, 1, '2001-01-01', '2001-01-31');
insert into @example values (2, 0, '2001-02-01', '2001-02-20');
insert into @example values (2, 0, '2001-02-21', '2001-02-28');
insert into @example values (2, 1, '2001-03-01', '2001-03-15');
declare @output table (tKey int, Valid int, DateFrom date, DateTo date);
DECLARE ex_cursor CURSOR FOR
select
tKey,Valid,DateFrom,DateTo
from
@example
order by tKey, DateFrom
DECLARE @tKey int
DECLARE @Valid int
DECLARE @DateFrom date
DECLARE @DateTo date
DECLARE @last_tKey int
DECLARE @last_Valid int
DECLARE @min_Date date
DECLARE @max_Date date
OPEN ex_cursor;
FETCH NEXT FROM ex_cursor
INTO @tKey, @Valid, @DateFrom, @DateTo;
SET @last_tKey = @tKey;
SET @last_Valid = @Valid;
SET @min_Date = @DateFrom;
SET @max_Date = @DateTo;
WHILE @@FETCH_STATUS = 0
BEGIN
IF (@last_tKey <> @tKey OR @last_Valid <> @Valid)
BEGIN
-- output results
INSERT INTO @output SELECT @last_tKey, @last_Valid, @min_Date, @max_Date
-- reset values
SET @last_tKey = @tKey;
SET @last_Valid = @Valid;
SET @min_Date = @DateFrom;
SET @max_Date = @DateTo;
END
ELSE
BEGIN
IF (@DateTo > @max_Date) SET @max_Date = @DateTo
END
FETCH NEXT FROM ex_cursor
INTO @tKey, @Valid, @DateFrom, @DateTo
END
-- output one more time at end
INSERT INTO @output SELECT @last_tKey, @last_Valid, @min_Date, @max_Date
CLOSE ex_cursor;
DEALLOCATE ex_cursor;
SELECT * FROM @output ORDER BY tKey, DateFrom
您的源数据中是否存在任何缺口或重叠?您可以使用任何提供的解决方案吗?是的,现在回答-感谢大家的建议-非常感激如果同一个密钥、有效组合有3个或更多连续记录会怎么样?@Dems这应该仍然有效,代码通过查找没有直接前面记录的记录来查找切换点。然后在那些关键的框架上迭代,我的坏。我只是粗略地浏览了一下这个问题,并假设它的作用是错误的。有一个角落的情况,这可能无法处理,虽然。。。如果我添加了记录| 1 | 0 | 2001-03-16 | 2001-03-31 |,最终结果是否仍然显示日期到值2001-03-15?我现在已经进行了适当的更正,代码现在将处理序列中的角情况和间隙。重叠是完全不同的情况!正如答案开头所暗示的那样;虽然这确实有效,但游标通常会产生巨大的成本——如果有一种基于集合的方法,那么首先需要探讨的是……没有间隙或重叠