【问题标题】:How to get next row value based on previous row excluding week ends in SQL Server?如何根据前一行获取下一行值,不包括 SQL Server 中的周末?
【发布时间】:2021-04-22 13:24:55
【问题描述】:

我有一张表如下:(没有周末排除逻辑的预期结果)

Start Date End Date(Expected Date) No of Days(input)
01-01-2021 02-01-2021 2
03-01-2021 08-01-2021 5
09-01-2021 10-01-2021 2
11-01-2021 20-01-2021 10
21-01-2021 09-02-2021 20
10-02-2021 10-02-2021 1

我想根据NumberOfDays 值重新生成StartDateEndDate 数据,并根据前一行的EndDate + 1 day 为后续行重新生成StartDate,在这个序列中,我需要也排除周末日期,我还有另一种情况可以根据情况包括周末日期。

我想应用此逻辑并使用 SQL Server 在同一选择查询中选择数据。

这是我尝试过的

declare @t table ( StartDate date, EndDate date, DaysToAdd int );

insert into @t(StartDate, EndDate, DaysToAdd)
 values('20210217', '20210227', 10), ('20210312', '20210310', 10), ('20210326', '20210401', 10), ('20210409', '20210401', 10), ('20210507', '20210401', 10), ('20210606', '20210529', 10), ('20210618', '20210417', 3), ('20210620', '20210309', 2), ('20300913', '20210227', 2), (null, '20300914', 4);

select * from @t

select dateadd(day, -DaysToAdd-1+count(*) over(order by isnull(StartDate, EndDate), EndDate) + sum(DaysToAdd) over(order by isnull(StartDate, EndDate), EndDate), min(StartDate) over()) as NewStartDate, dateadd(day, -1+count(*) over(order by isnull(StartDate, EndDate), EndDate) + sum(DaysToAdd) over(order by isnull(StartDate, EndDate), EndDate), min(StartDate) over()) as NewEndDate, * from @t;

我的预期结果:

Start Date End Date(Expected Date) No of Days(input)
01-01-2021 04-01-2021 2
05-01-2021 11-01-2021 5
12-01-2021 13-01-2021 2
14-01-2021 27-01-2021 10
28-01-2021 24-02-2021 20
25-02-2021 25-02-2021 1

【问题讨论】:

  • 请与我们分享您的尝试
  • 还有其他列可以订购吗?像主键一样?您要求更改 StartDateEndDate 的值。然后,您将如何确定处理行的顺序?
  • 我在排序顺序中有另一列根据此列进行排序。
  • 向我们展示您的预期结果将有助于我们为您提供帮助。
  • @Larnu,以上表格格式结果需要我

标签: sql-server sorting lead


【解决方案1】:

最好有日历表

对于解决方案,我创建了一个简单的calendar

create table calendar
(
    CalDate      date,
    isWeekEnd    bit
);

然后用日期填充它

with rcte as
(
    select CalDate = convert(date, '2021-01-01')
    union all
    select CalDate = dateadd(day, 1, CalDate)
    from   rcte
    where  CalDate <= '2021-12-30'
)
insert into calendar (CalDate, isWeekEnd)
select CalDate, 
       case when left(datename(weekday, CalDate), 3) in ('Sat', 'Sun') then 1 else 0 end
from   rcte
option (maxrecursion 0)

您的示例表和数据

declare @t table (id int identity, StartDate date, EndDate date, DaysToAdd int );

insert into @t(StartDate, EndDate, DaysToAdd)
values('2021-01-01', '2021-01-02', 2), 
      ('2021-01-03', '2021-01-08', 5), 
      ('2021-01-09', '2021-01-10', 2), 
      ('2021-01-11', '2021-01-20', 10), 
      ('2021-01-21', '2021-02-09', 20), 
      ('2021-02-10', '2021-02-10', 1);

由于您只对第一行的StartDate 感兴趣,所以我将其选择为变量

实际查询

declare @StartDate date;

select @StartDate = StartDate
from   @t
where  id = 1;

with 
cal as
(
    select CalDate, rn = row_number() over (order by CalDate)
    from   Calendar
    where  CalDate  >= @StartDate
    and    isWeekEnd = 0
),
t as
(
    select t.id, t.DaysToAdd,
           s = sum(t.DaysToAdd) over (order by t.id) - t.DaysToAdd + 1,
           e = sum(t.DaysToAdd) over (order by t.id)
    from   @t t
)
select t.id, 
       t.DaysToAdd,
       StartDate = s.CalDate,
       EndDate   = e.CalDate
from   t
       inner join cal s on t.s = s.rn
       inner join cal e on t.e = e.rn
order by t.id

db<>fiddle demo

【讨论】:

  • 感谢@Squirrel,它给出了预期的结果,但在我们的例子中,我们需要在没有calendar 表的情况下实现这一点,这里的开始将是动态的,在某些情况下我们可能有 2 年的合同.所以我们必须在计算StartDate/EndDate时检查是否是周末。有没有直接的解决方案?在此先感谢...!
  • 如果您正在处理日期和周末,您应该认真考虑使用日历表。它使事情变得容易得多。如果出于某种原因你真的不能有一个日历表,你可以在 CTE 中基于 min (date)max(date) 动态生成它
猜你喜欢
  • 2021-04-16
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多