Sql 游标/递归是这里唯一可能的选项吗?基于特定滞后条件的集合逻辑
我使用的是SQL Server,我有一个包含3列timeseries数据的表,其中包含日期、小时开始时间和获奖状态 大部分的奖励状态是随机生成的。有两种选择,授予或不授予 但是,业务要求是,如果状态为NotAwarded,我们必须连续打印3行“NotAwarded”,如果状态为Deward,则必须连续打印4行 目标:一个新的专栏应该是详细信息 一旦满足最低要求,它将检查当前行的AwardStatus并继续覆盖逻辑 问:在SQL中,没有任何类型的游标/循环,这可能吗 下面的图片是一个例子 下面是一个例子:Sql 游标/递归是这里唯一可能的选项吗?基于特定滞后条件的集合逻辑,sql,sql-server,Sql,Sql Server,我使用的是SQL Server,我有一个包含3列timeseries数据的表,其中包含日期、小时开始时间和获奖状态 大部分的奖励状态是随机生成的。有两种选择,授予或不授予 但是,业务要求是,如果状态为NotAwarded,我们必须连续打印3行“NotAwarded”,如果状态为Deward,则必须连续打印4行 目标:一个新的专栏应该是详细信息 一旦满足最低要求,它将检查当前行的AwardStatus并继续覆盖逻辑 问:在SQL中,没有任何类型的游标/循环,这可能吗 下面的图片是一个例子 下面是一
AwardStatusMinimum 3
AwardStatusMaximum 4
Date Hour AwardStatus ShouldBe
--------------------------------------
1/1/2019 1 NotAwarded NotAwarded
1/1/2019 2 NotAwarded NotAwarded
1/1/2019 3 Awarded NotAwarded
1/1/2019 4 Awarded Awarded
1/1/2019 5 NotAwarded Awarded
1/1/2019 6 NotAwarded Awarded
1/1/2019 7 Awarded Awarded
1/1/2019 8 NotAwarded NotAwarded
1/1/2019 9 Awarded NotAwarded
1/1/2019 10 Awarded NotAwarded
这使您无需使用光标即可完成此操作
declare @date date
declare @hour int
declare @CurrentStatus varchar(50)
set @CurrentStatus=''
while exists(select * from Awards where ShouldBe is null)
begin
select top 1 @date=[date], @hour=[hour] , @CurrentStatus=AwardStatus
from Awards
where [ShouldBe] is null
order by [date],[hour]
if(@CurrentStatus='Awarded')
begin
update top(4) Awards
set ShouldBe=@CurrentStatus
where [date]=@date and [hour]>=@hour
end
else
begin
update top(3) Awards
set ShouldBe=@CurrentStatus
where [date]=@date and [hour]>=@hour
end
end
因为提到了递归 这里有一个使用递归CTE的解决方案 样本数据: 查询:
dbfiddle上的一个测试嗨,欢迎来到SO。没有图片链接,请键入数据示例和模式以帮助我们。看,对不起!新这里,刚刚添加了代码文本!!我认为这可能是你问题的解决方案,我们希望这样:在原始帖子中添加,谢谢horaciux,这将确保这就是我今后提问的方式。
CREATE TABLE Table1 (
[Date] DATETIME NOT NULL,
[Hour] INT NOT NULL,
[AwardStatus] VARCHAR(10)
);
INSERT INTO Table1
([Date], [Hour], [AwardStatus])
VALUES
('2019-01-01', 1, 'NotAwarded'),
('2019-01-01', 2, 'NotAwarded'),
('2019-01-01', 3, 'Awarded'),
('2019-01-01', 4, 'Awarded'),
('2019-01-01', 5, 'NotAwarded'),
('2019-01-01', 6, 'NotAwarded'),
('2019-01-01', 7, 'Awarded'),
('2019-01-01', 8, 'NotAwarded'),
('2019-01-01', 9, 'Awarded'),
('2019-01-01', 10, 'Awarded');
;with CTE_DATA AS
(
select *
, dense_rank()
over (order by cast([Date] as date)) as grp
, row_number()
over (partition by cast([Date] as date) order by [Hour]) as rn
from Table1
)
, RCTE_AWARDS as
(
select [Date], [Hour]
, AwardStatus
, grp
, rn
, 1 as Lvl
, AwardStatus AS CalcStatus
from CTE_DATA
where rn = 1
union all
select t.[Date], t.[Hour]
, t.AwardStatus
, t.grp
, t.rn
, case
when (c.lvl < 3)
or (c.lvl < 4 and c.CalcStatus = 'Awarded')
then c.lvl+1
else 1
end
, case
when (c.lvl = 3 and c.CalcStatus = 'NotAwarded')
or (c.lvl = 4)
then t.AwardStatus
else c.CalcStatus
end
from RCTE_AWARDS c
join CTE_DATA t
on t.grp = c.grp
and t.rn = c.rn + 1
)
select [Date], [Hour], AwardStatus
, CalcStatus AS NewAwardStatus
from RCTE_AWARDS
order by [Date], [Hour]
GO
Date | Hour | AwardStatus | NewAwardStatus
:---------------------- | ---: | :---------- | :-------------
2019-01-01 00:00:00.000 | 1 | NotAwarded | NotAwarded
2019-01-01 00:00:00.000 | 2 | NotAwarded | NotAwarded
2019-01-01 00:00:00.000 | 3 | Awarded | NotAwarded
2019-01-01 00:00:00.000 | 4 | Awarded | Awarded
2019-01-01 00:00:00.000 | 5 | NotAwarded | Awarded
2019-01-01 00:00:00.000 | 6 | NotAwarded | Awarded
2019-01-01 00:00:00.000 | 7 | Awarded | Awarded
2019-01-01 00:00:00.000 | 8 | NotAwarded | NotAwarded
2019-01-01 00:00:00.000 | 9 | Awarded | NotAwarded
2019-01-01 00:00:00.000 | 10 | Awarded | NotAwarded