我遇到了将相同类型的记录与连续序列合并并从合并记录中计算完整序列的问题。
排序应该在基础ID上完成,因为当序列达到100时序列可能翻转为0.参见输入/输出示例中的最后一项。
是否可以使用下面列出的输入并生成一个产生输出的查询,该输出也在下面的SQL Server 2012中列出?
输入
Id Type Begin End
-----------------------------
1 1 10 20
2 1 21 23
3 2 24 28
4 1 29 40
5 2 41 47
6 2 48 50
7 2 75 80
8 1 81 100
9 1 0 10
10 1 11 20
11 1 21 5
12 1 5 6
输出
FromId ToId Type Begin End Length
----------------------------------------------------
1 2 1 10 23 13 (23-19)
3 3 2 24 28 4 (28-24)
4 4 1 29 40 11 (40-29)
5 6 2 41 50 9 (50-41)
7 7 2 75 80 5 (80 - 75)
8 12 1 81 20 227*
*(100-81)+ 10 +(100-11 + 20)+(100-21 + 5)+ 1 - > 翻转seq
请注意,源中的第6行和第7行未合并,因为它们不是连续的。第6行以50结尾,第7行以75开头。只需要合并具有相同类型的连续行。
答案 0 :(得分:3)
你的最后一行有Begin = 10,这与其他人没有遵循相同的规则。我在我的例子中更新了11。希望这会有所帮助。
WITH typeRowNum AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Id ASC) AS rownum
FROM tblType
)
,rw AS (
SELECT t1.*,
CASE WHEN t1.[type] = t2.[type] and ( t1.[Begin] = t2. [end] + 1 OR t1.[Begin] + 100 = t2.[end])
THEN -1
ELSE t1.rownum
END AS group_id
FROM typeRowNum t1
LEFT JOIN typeRowNum t2
ON t2.rownum = t1.rownum - 1
)
, cte AS (
SELECT *,
new_end = ISNULL(
(SELECT MIN(rownum) - 1 FROM rw r2 WHERE r2.rownum > r1.rownum and r2.group_id > r1.group_id),
(SELECT MAX(rownum) FROM rw)
)
FROM rw r1
WHERE r1.group_id > 0
)
select
c1.id,c1.type,c1.[begin],c2.[end]
,[length] = (SELECT SUM((r.[end] - r.[Begin]
+ CASE WHEN r.[end] < r.[Begin] THEN 100 ELSE 0 END
+ CASE WHEN (r.group_id = -1) AND (r.[Begin] < r.[End]) THEN 1 ELSE 0 END)
)
FROM rw r WHERE r.rownum BETWEEN c1.[rownum] AND c2.[rownum])
FROM cte c1
LEFT JOIN rw c2
ON c1.new_end = c2.rownum
UPDATE:如果您有NULL值,则很可能您在[Id]列中有一些已停止的值。相反,您可以使用Row_Number来加入。我更新了上面的答案。
答案 1 :(得分:1)
Type IntervalBegin CurrEnd
1 10 20
1 NULL 23
2 24 28
1 29 40
2 41 47
2 NULL 50
2 75 80
1 81 100
1 NULL 10
1 10 20
但我仍然对汇总收到的结果感到困惑......
查询在
之下DECLARE @MyTable TABLE ([Id] INT, [Type] INT, [Begin] INT, [End] INT)
INSERT INTO @MyTable([Id], [Type], [Begin], [End] )
VALUES
(1, 1, 10, 20),
(2, 1, 21, 23),
(3, 2, 24, 28),
(4, 1, 29, 40),
(5, 2, 41, 47),
(6, 2, 48, 50),
(7, 2, 75, 80),
(8, 1, 81, 100),
(9, 1, 0, 10),
(10, 1, 10, 20)
SELECT
[Type],
CASE
WHEN ShouldCompareWithPrevious = 1 AND PrevBegin IS NULL THEN CurrBegin
WHEN ShouldCompareWithPrevious = 1 AND PrevEnd = 100 AND CurrBegin = 0 THEN NULL
WHEN ShouldCompareWithPrevious = 1 AND PrevEnd + 1 <> CurrBegin THEN CurrBegin
WHEN ShouldCompareWithPrevious = 0 THEN CurrBegin
ELSE NULL
END IntervalBegin,
CurrEnd
FROM
(
SELECT t1.[Id], t2.[Id] t2Id,
t1.[Type], t2.[Type] t2Type,
(
CASE
WHEN t2.[Type] IS NULL THEN 0
WHEN t2.[Type] = t1.[Type] THEN 1
ELSE
0
END
) AS ShouldCompareWithPrevious,
t1.[Begin] CurrBegin,
t1.[End] CurrEnd,
t2.[Begin] PrevBegin,
t2.[End] PrevEnd
FROM @MyTable t1
LEFT OUTER JOIN @MyTable t2
ON t1.Id = t2.Id + 1
) intermideate
答案 2 :(得分:0)
这个问题通常可以通过这样的递归来解决:
create table #t ([Id] int, [Type] int, [Begin] int, [End] int);
insert into #t values (1,1,10,20),(2,1,21,23),(3,2,24,28),(4,1,29,40),
(5,2,41,47),(6,2,48,50),(7,2,75,80),(8,1,81,100),(9,1,0,10),(10,1,10,20);
with cRek as (
-- records with no followup
select t.[Type], FromId = t.[Id], ToId = t.[Id],
t.[Begin], t.[End], [Length] = t.[End]-t.[Begin]+1
from #t t
left join #t tf
on tf.[Type] = t.[Type]
and tf.[Begin] = (t.[End]+1)%101
and tf.[Id] > t.[Id]
where tf.[Id] is null
union all
-- previous record
select t.[Type], FromId = t.[Id], ToId = tf.[ToId],
t.[Begin], tf.[End], [Length] = tf.[Length]+t.[End]-t.[Begin]+1
from #t t
inner join cRek tf
on tf.[Type] = t.[Type]
and tf.[Begin] = (t.[End]+1)%101
and tf.[FromId] > t.[Id]
)
select *
from cRek r
where FromId =
(select min(x.FromId)
from cRek x
where x.[Type]=r.[Type] and x.[ToId]=r.[ToId])
order by ToId;
drop table #t;
您的样本有一些小缺陷:
HTH,Manfred