【问题标题】:Get Week Start and End Dates获取周开始和结束日期
【发布时间】:2021-06-16 07:18:22
【问题描述】:

我需要从当前月份获取所有星期的开始和结束日期,假设我的一周从 星期六 开始并在 星期五 结束,我尝试过以下...

以下查询是表值函数的一部分,我在其中传递当前月份的开始日期并返回表运行时。

Declare @fromDate date
DECLARE @date date = GETUTCDATE()
DECLARE @tmpWeeks Table([WeekStart] date, [WeekEnd] date)
SET @fromDate = CAST(DATEADD(month, DATEDIFF(month, 0, @date), 0) as date)
    ;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
   , dates as (
select top (datediff(day, @fromdate, dateadd(month, datediff(month, 0, @fromdate )+1, 0))) [DateValue]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto
)
Insert into @tmpWeeks
select 
WeekStart   = min(DateValue), WeekEnd = max(DateValue)
from dates
group by datepart(week,DateValue)
select * from @tmpWeeks

它给了我以下结果。

WeekStart  WeekEnd
---------- ----------
2021-06-01 2021-06-04
2021-06-05 2021-06-11
2021-06-12 2021-06-18
2021-06-19 2021-06-25
2021-06-26 2021-06-30

上面的结果部分正确,但是,如果我们在这里看到第一条记录的WeekStart 日期是2021-06-01,但它应该有2021-05-29 (周六)

最后一条记录同样显示WeekEnd 2021-06-30 但它应该有 2021-07-02

所以在考虑了上述条件后,预期结果将如下所示..

WeekStart  WeekEnd
---------- ----------
2021-05-29 2021-06-04
2021-06-05 2021-06-11
2021-06-12 2021-06-18
2021-06-19 2021-06-25
2021-06-26 2021-07-02

任何帮助!?

【问题讨论】:

  • 解决这个问题的典型方法是创建 a Calendar table 并预先计算未来的日期,例如 10-20 年,并为年、月、季度、学期、周数添加额外的列(可能已编入索引) ,星期开始和结束,日期名称等。表格的大小非常小。查询变得容易得多,性能也提高了几个数量级。过去需要全表扫描和计算的东西变成了对索引列的简单分组

标签: sql sql-server tsql


【解决方案1】:

稍微调整了 OP 版本

Declare @fromDate date;
DECLARE @date date = GETUTCDATE();
declare @m int = month(@date);
-- -2 to shift start of week to Saturday
-- -5 to shift start to a previous month
SET @fromDate = DATEADD(week, DATEDIFF(week, 0, @date) - 5, 0) -2;
-- 11 weeks to cover month of interest fo sure
with t as (
    select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(n) )
, dates as (
    select [DateS] = dateadd(week, n, @fromdate)
    from t 
)
-- take current month only
select [DateS], dateadd(dd, 6, [DateS]) [DateE]
from dates
where @m in (month([DateS]), month(dateadd(dd, 6, [DateS])));

【讨论】:

    【解决方案2】:

    您可以使用这样的查询来做到这一点:

    declare @fromDate date = '06-02-2021'
    
    set @fromDate = 
      case datepart(dw,@fromDate)
        when 7 then @fromDate
        else dateadd(day, - datepart(dw,@fromDate), @fromDate)
      end
    
    ;with weeks as (
      select datepart(week, @fromDate) w, @fromDate d, datepart(weekday, @fromDate) dd
      union all
      select datepart(week, dateadd(day, 1, d)), dateadd(day, 1, d), datepart(weekday, dateadd(day, 1, d)) from weeks where d <= '2022-01-01'
    )
    select dateadd(day, -1, min(d)) as weekstart, max(d) as weekend
    from weeks
    where dd in (1,6)
    group by w
    option (maxrecursion 0)
    

    你可以在这个db<>fiddle上测试

    递归 cte 可以很好地自动生成日期,就像你的情况一样。

    【讨论】:

    • 谢谢回答,我试过了,最后一条记录是正确的,但是第一条记录显示错误WeekStart日期,你能帮忙吗?
    • 只需在上方选择中将'06-01-2021' 替换为您的开始日期'2021-05-29'(出现3 次)
    • 这是我想要的结果,有没有办法让我们更自动地做到这一点?
    • 你的问题不清楚。您想构建一个包含开始/结束日期的表,还是想在运行时构建它?请说清楚。
    • 我已经编辑了这个问题,并且我将一个月的第一天作为参数传递,结果它返回了我的表格。