获取每月每周的开始和结束日期

时间:2017-03-14 19:24:31

标签: sql-server tsql sql-server-2012

我需要在给定的月/年中获得每周的开始和结束日期。 (总是给出月份和年份 - 就像2017年3月)。

示例,2017年1月:

1 week : '2017-01-01' - '2017-01-01'
2 week:  '2017-01-02' - '2017-01-08'
3 week:  '2017-01-09' - '2017-01-15'
4 week:  '2017-01-16' - '2017-01-22'
5 week:  '2017-01-23' - '2017-01-29'
6 week:  '2017-01-30' - '2017-01-31'

enter image description here

我已经know如何获得给定月/年的周数:

select *,
    DATEDIFF(WEEK, DATEADD(day,-1,StartAt), DATEADD(day,-1,EndAt)) +1
    as NumWeeks

但是如何获得给定月/年的每周开始/结束日期?

6 个答案:

答案 0 :(得分:1)

select 
    DateValue
  , WeekStart =convert(date,(
    case when datepart(week,DateValue) =1 
      then convert(date, (datename(year,DateValue) +'0101')) 
      else dateadd(day,@@datefirst-datepart(weekday,DateValue)-(@@datefirst-1),DateValue)
      end) ) 
  , WeekEnd  =convert(date,(
    case when datepart(week,DateValue) =53 
      then convert(date, (datename(year,DateValue) +'1231')) 
      else dateadd(day,(@@datefirst)-datepart(weekday,DateValue)+(7-@@datefirst),DateValue)
      end) ) 
from dates

rextester演示:http://rextester.com/KYKS44588

测试设置:

set datefirst 1;
declare @fromdate date = '20161227', @thrudate date = '20201231';
;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, @thrudate)+1) 
    [DateValue]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
  from n as deka cross join n as hecto cross join n as kilo cross join n as [tenK] 
  order by 1
)
, test as (
  select 
      convert(varchar(10),DateValue,120) as Date
    , WeekStart = convert(varchar(10),convert(date,(
        case when datepart(week,DateValue) =1 
          then convert(date, (datename(year,DateValue) +'0101')) 
        else dateadd(day,@@datefirst-datepart(WeekDay,DateValue)-(@@datefirst-1),DateValue)
        end) ),120)
    , WeekEnd  = convert(varchar(10),convert(date,(
        case when datepart(week,DateValue) =53 
          then convert(date, (datename(year,DateValue) +'1231')) 
        else dateadd(day,(@@datefirst)-datepart(WeekDay,DateValue)+(7-@@datefirst),DateValue)
        end) ),120)
    , week= datepart(week,DateValue)

  from dates
)
select *
  , dayname= datename(weekday,date) 
  , weekstartdayname= datename(weekday,weekstart) 
  , weekenddayname= datename(weekday,weekend) 
from test
where week > 51
   or week < 3
order by 1

结果:

+------------+------------+------------+------+-----------+------------------+----------------+
|    Date    | WeekStart  |  WeekEnd   | week |  dayname  | weekstartdayname | weekenddayname |
+------------+------------+------------+------+-----------+------------------+----------------+
| 2016-12-27 | 2016-12-26 | 2016-12-31 |   53 | Tuesday   | Monday           | Saturday       |
| 2016-12-28 | 2016-12-26 | 2016-12-31 |   53 | Wednesday | Monday           | Saturday       |
| 2016-12-29 | 2016-12-26 | 2016-12-31 |   53 | Thursday  | Monday           | Saturday       |
| 2016-12-30 | 2016-12-26 | 2016-12-31 |   53 | Friday    | Monday           | Saturday       |
| 2016-12-31 | 2016-12-26 | 2016-12-31 |   53 | Saturday  | Monday           | Saturday       |
| 2017-01-01 | 2017-01-01 | 2017-01-01 |    1 | Sunday    | Sunday           | Sunday         |
| 2017-01-02 | 2017-01-02 | 2017-01-08 |    2 | Monday    | Monday           | Sunday         |
| 2017-01-03 | 2017-01-02 | 2017-01-08 |    2 | Tuesday   | Monday           | Sunday         |
| 2017-01-04 | 2017-01-02 | 2017-01-08 |    2 | Wednesday | Monday           | Sunday         |
| 2017-01-05 | 2017-01-02 | 2017-01-08 |    2 | Thursday  | Monday           | Sunday         |
| 2017-01-06 | 2017-01-02 | 2017-01-08 |    2 | Friday    | Monday           | Sunday         |
| 2017-01-07 | 2017-01-02 | 2017-01-08 |    2 | Saturday  | Monday           | Sunday         |
| 2017-01-08 | 2017-01-02 | 2017-01-08 |    2 | Sunday    | Monday           | Sunday         |
| 2017-12-18 | 2017-12-18 | 2017-12-24 |   52 | Monday    | Monday           | Sunday         |
| 2017-12-19 | 2017-12-18 | 2017-12-24 |   52 | Tuesday   | Monday           | Sunday         |
| 2017-12-20 | 2017-12-18 | 2017-12-24 |   52 | Wednesday | Monday           | Sunday         |
| 2017-12-21 | 2017-12-18 | 2017-12-24 |   52 | Thursday  | Monday           | Sunday         |
| 2017-12-22 | 2017-12-18 | 2017-12-24 |   52 | Friday    | Monday           | Sunday         |
| 2017-12-23 | 2017-12-18 | 2017-12-24 |   52 | Saturday  | Monday           | Sunday         |
| 2017-12-24 | 2017-12-18 | 2017-12-24 |   52 | Sunday    | Monday           | Sunday         |
| 2017-12-25 | 2017-12-25 | 2017-12-31 |   53 | Monday    | Monday           | Sunday         |
| 2017-12-26 | 2017-12-25 | 2017-12-31 |   53 | Tuesday   | Monday           | Sunday         |
| 2017-12-27 | 2017-12-25 | 2017-12-31 |   53 | Wednesday | Monday           | Sunday         |
| 2017-12-28 | 2017-12-25 | 2017-12-31 |   53 | Thursday  | Monday           | Sunday         |
| 2017-12-29 | 2017-12-25 | 2017-12-31 |   53 | Friday    | Monday           | Sunday         |
| 2017-12-30 | 2017-12-25 | 2017-12-31 |   53 | Saturday  | Monday           | Sunday         |
| 2017-12-31 | 2017-12-25 | 2017-12-31 |   53 | Sunday    | Monday           | Sunday         |
| 2018-01-01 | 2018-01-01 | 2018-01-07 |    1 | Monday    | Monday           | Sunday         |
| 2018-01-02 | 2018-01-01 | 2018-01-07 |    1 | Tuesday   | Monday           | Sunday         |
| 2018-01-03 | 2018-01-01 | 2018-01-07 |    1 | Wednesday | Monday           | Sunday         |
| 2018-01-04 | 2018-01-01 | 2018-01-07 |    1 | Thursday  | Monday           | Sunday         |
| 2018-01-05 | 2018-01-01 | 2018-01-07 |    1 | Friday    | Monday           | Sunday         |
| 2018-01-06 | 2018-01-01 | 2018-01-07 |    1 | Saturday  | Monday           | Sunday         |
| 2018-01-07 | 2018-01-01 | 2018-01-07 |    1 | Sunday    | Monday           | Sunday         |
| 2018-01-08 | 2018-01-08 | 2018-01-14 |    2 | Monday    | Monday           | Sunday         |
| 2018-01-09 | 2018-01-08 | 2018-01-14 |    2 | Tuesday   | Monday           | Sunday         |
| 2018-01-10 | 2018-01-08 | 2018-01-14 |    2 | Wednesday | Monday           | Sunday         |
| 2018-01-11 | 2018-01-08 | 2018-01-14 |    2 | Thursday  | Monday           | Sunday         |
| 2018-01-12 | 2018-01-08 | 2018-01-14 |    2 | Friday    | Monday           | Sunday         |
| 2018-01-13 | 2018-01-08 | 2018-01-14 |    2 | Saturday  | Monday           | Sunday         |
| 2018-01-14 | 2018-01-08 | 2018-01-14 |    2 | Sunday    | Monday           | Sunday         |
| 2018-12-24 | 2018-12-24 | 2018-12-30 |   52 | Monday    | Monday           | Sunday         |
| 2018-12-25 | 2018-12-24 | 2018-12-30 |   52 | Tuesday   | Monday           | Sunday         |
| 2018-12-26 | 2018-12-24 | 2018-12-30 |   52 | Wednesday | Monday           | Sunday         |
| 2018-12-27 | 2018-12-24 | 2018-12-30 |   52 | Thursday  | Monday           | Sunday         |
| 2018-12-28 | 2018-12-24 | 2018-12-30 |   52 | Friday    | Monday           | Sunday         |
| 2018-12-29 | 2018-12-24 | 2018-12-30 |   52 | Saturday  | Monday           | Sunday         |
| 2018-12-30 | 2018-12-24 | 2018-12-30 |   52 | Sunday    | Monday           | Sunday         |
| 2018-12-31 | 2018-12-31 | 2018-12-31 |   53 | Monday    | Monday           | Monday         |
| 2019-01-01 | 2019-01-01 | 2019-01-06 |    1 | Tuesday   | Tuesday          | Sunday         |
| 2019-01-02 | 2019-01-01 | 2019-01-06 |    1 | Wednesday | Tuesday          | Sunday         |
| 2019-01-03 | 2019-01-01 | 2019-01-06 |    1 | Thursday  | Tuesday          | Sunday         |
| 2019-01-04 | 2019-01-01 | 2019-01-06 |    1 | Friday    | Tuesday          | Sunday         |
| 2019-01-05 | 2019-01-01 | 2019-01-06 |    1 | Saturday  | Tuesday          | Sunday         |
| 2019-01-06 | 2019-01-01 | 2019-01-06 |    1 | Sunday    | Tuesday          | Sunday         |
| 2019-01-07 | 2019-01-07 | 2019-01-13 |    2 | Monday    | Monday           | Sunday         |
| 2019-01-08 | 2019-01-07 | 2019-01-13 |    2 | Tuesday   | Monday           | Sunday         |
| 2019-01-09 | 2019-01-07 | 2019-01-13 |    2 | Wednesday | Monday           | Sunday         |
| 2019-01-10 | 2019-01-07 | 2019-01-13 |    2 | Thursday  | Monday           | Sunday         |
| 2019-01-11 | 2019-01-07 | 2019-01-13 |    2 | Friday    | Monday           | Sunday         |
| 2019-01-12 | 2019-01-07 | 2019-01-13 |    2 | Saturday  | Monday           | Sunday         |
| 2019-01-13 | 2019-01-07 | 2019-01-13 |    2 | Sunday    | Monday           | Sunday         |
| 2019-12-23 | 2019-12-23 | 2019-12-29 |   52 | Monday    | Monday           | Sunday         |
| 2019-12-24 | 2019-12-23 | 2019-12-29 |   52 | Tuesday   | Monday           | Sunday         |
| 2019-12-25 | 2019-12-23 | 2019-12-29 |   52 | Wednesday | Monday           | Sunday         |
| 2019-12-26 | 2019-12-23 | 2019-12-29 |   52 | Thursday  | Monday           | Sunday         |
| 2019-12-27 | 2019-12-23 | 2019-12-29 |   52 | Friday    | Monday           | Sunday         |
| 2019-12-28 | 2019-12-23 | 2019-12-29 |   52 | Saturday  | Monday           | Sunday         |
| 2019-12-29 | 2019-12-23 | 2019-12-29 |   52 | Sunday    | Monday           | Sunday         |
| 2019-12-30 | 2019-12-30 | 2019-12-31 |   53 | Monday    | Monday           | Tuesday        |
| 2019-12-31 | 2019-12-30 | 2019-12-31 |   53 | Tuesday   | Monday           | Tuesday        |
| 2020-01-01 | 2020-01-01 | 2020-01-05 |    1 | Wednesday | Wednesday        | Sunday         |
| 2020-01-02 | 2020-01-01 | 2020-01-05 |    1 | Thursday  | Wednesday        | Sunday         |
| 2020-01-03 | 2020-01-01 | 2020-01-05 |    1 | Friday    | Wednesday        | Sunday         |
| 2020-01-04 | 2020-01-01 | 2020-01-05 |    1 | Saturday  | Wednesday        | Sunday         |
| 2020-01-05 | 2020-01-01 | 2020-01-05 |    1 | Sunday    | Wednesday        | Sunday         |
| 2020-01-06 | 2020-01-06 | 2020-01-12 |    2 | Monday    | Monday           | Sunday         |
| 2020-01-07 | 2020-01-06 | 2020-01-12 |    2 | Tuesday   | Monday           | Sunday         |
| 2020-01-08 | 2020-01-06 | 2020-01-12 |    2 | Wednesday | Monday           | Sunday         |
| 2020-01-09 | 2020-01-06 | 2020-01-12 |    2 | Thursday  | Monday           | Sunday         |
| 2020-01-10 | 2020-01-06 | 2020-01-12 |    2 | Friday    | Monday           | Sunday         |
| 2020-01-11 | 2020-01-06 | 2020-01-12 |    2 | Saturday  | Monday           | Sunday         |
| 2020-01-12 | 2020-01-06 | 2020-01-12 |    2 | Sunday    | Monday           | Sunday         |
| 2020-12-21 | 2020-12-21 | 2020-12-27 |   52 | Monday    | Monday           | Sunday         |
| 2020-12-22 | 2020-12-21 | 2020-12-27 |   52 | Tuesday   | Monday           | Sunday         |
| 2020-12-23 | 2020-12-21 | 2020-12-27 |   52 | Wednesday | Monday           | Sunday         |
| 2020-12-24 | 2020-12-21 | 2020-12-27 |   52 | Thursday  | Monday           | Sunday         |
| 2020-12-25 | 2020-12-21 | 2020-12-27 |   52 | Friday    | Monday           | Sunday         |
| 2020-12-26 | 2020-12-21 | 2020-12-27 |   52 | Saturday  | Monday           | Sunday         |
| 2020-12-27 | 2020-12-21 | 2020-12-27 |   52 | Sunday    | Monday           | Sunday         |
| 2020-12-28 | 2020-12-28 | 2020-12-31 |   53 | Monday    | Monday           | Thursday       |
| 2020-12-29 | 2020-12-28 | 2020-12-31 |   53 | Tuesday   | Monday           | Thursday       |
| 2020-12-30 | 2020-12-28 | 2020-12-31 |   53 | Wednesday | Monday           | Thursday       |
| 2020-12-31 | 2020-12-28 | 2020-12-31 |   53 | Thursday  | Monday           | Thursday       |
+------------+------------+------------+------+-----------+------------------+----------------+

日历和数字表格引用:

答案 1 :(得分:1)

这样的东西?

DECLARE @Dates TABLE (DateId INT IDENTITY, Dt Date);

DECLARE @STart Date = DATEADD(Year, DATEDIFF(Year, 0, GETDATE()),0)

SET NOCOUNT ON;

WHILE @STart <= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)
BEGIN
        INSERT INTO @Dates (Dt) VALUES (@STart)

    SELECT @Start = DATEADD(DAY, 1, @STart)
END

<强>更新

SELECT 
  DateId
, Dt
, DATEADD(WEEK, DATEDIFF(DAY, 0, Dt)/7, 0) AS WeekBeginningMondayOf
, DATEADD(DAY, 6, DATEADD(WEEK, DATEDIFF(DAY, 0, Dt)/7, 0)) AS WeekEndingSundayOf
, DENSE_RANK() OVER(PARTITION BY MONTH(Dt) ORDER BY DATEADD(WEEK, DATEDIFF(DAY, 0, Dt)/7, 0)) AS WeekInMonth
FROM @Dates

答案 2 :(得分:1)

我认为你在寻找的是 - &gt; someone asked on stackoverflow与你正在寻找的相似。

这是最终版本,希望按照您的期望 我建立在上面的链接上希望这是你正在寻找的(apologies new to stackoverflow,unformatted t-sql下面)

DECLARE @sDate DATETIME,
        @eDate DATETIME

SET @sDate = '2017-03-01'
SET @eDate = DATEADD(DAY,-1, CAST(Cast(DatePart(YEAR,@sdate) AS varchar(4)) 
+'-' + Cast((DatePart(MONTH,@sdate)+1) AS varchar(2))+ '-1' AS Date))
SET @sDate = CAST(Cast(DatePart(YEAR,@sdate) AS varchar(4)) +'-' 
+ Cast(DatePart(MONTH,@sdate) AS varchar(2))+ '-1' AS Date) 

DECLARE @startDayOfWeekOffSet int ;
SET @startDayOfWeekOffSet=
  (SELECT DATEPART(DW,@sDate));

DECLARE @DaysToGetFirstSaturday int
SET @DaysToGetFirstSaturday= 7- @startDayOfWeekOffSet 
DECLARE @firstEverStartOfWeekDay Date , @firstWeekEndDay Date
SET @firstEverStartOfWeekDay =@sDate;

IF @startDayOfWeekOffSet = 1 -- January
BEGIN
SET @firstEverStartOfWeekDay = @sDate
SET @DaysToGetFirstSaturday = 0
SET @firstWeekEndDay = @sDate END 
ELSE BEGIN IF DATEPART(MONTH,@sDate) > DATEPART(MONTH,@firstEverStartOfWeekDay)
AND @startDayOfWeekOffSet = 7 --FirstSundayNewMonth
BEGIN
SET @firstEverStartOfWeekDay =@sDate
SET @firstWeekEndDay = @sDate END ELSE --NotASundayNewMonth
BEGIN
SET @firstWeekEndDay = DATEADD(DAY,@DaysToGetFirstSaturday,@firstEverStartOfWeekDay);

END END
SELECT @firstWeekEndDay AS firstWeekEndDay,
       @firstEverStartOfWeekDay AS firstEverStartOfWeekDay,
       @DaysToGetFirstSaturday AS DaysToGetFirstSaturday,
       @startDayOfWeekOffSet AS startDayOfWeekOffSet ;

WITH cte AS
  (SELECT 1 AS WeekNum,
          @firstEverStartOfWeekDay StartDate,
          @firstWeekEndDay EndDate
   UNION ALL SELECT WeekNum + 1, --Case when @scenario = 'NewYear' Then
 dateadd(DAY, 1, cte.EndDate) --Else dateadd(ww, 1, cte.StartDate) End as
 StartDate,
 CASE
     WHEN StartDate = EndDate THEN DateAdd(DAY,-1,dateadd(DAY, 8, cte.EndDate))
     ELSE dateadd(ww, 1, cte.EndDate)
 END AS EndDate
   FROM cte
   WHERE dateadd(ww, 1, StartDate)<= @eDate )
SELECT WeekNum,
       CASE
           WHEN DatePart(YEAR, StartDate) < DATEPART(YEAR,@sDate) 
                THEN CAST(Cast(DatePart(YEAR,@sdate) AS varchar(4)) + '-1-1' AS Date)
           WHEN DatePart(MONTH, StartDate) < DATEPART(MONTH,@sDate) 
                THEN CAST(Cast(DatePart(YEAR,@sdate) AS varchar(4)) + '-' 
                + Cast(DatePart(MONTH,@sdate) AS varchar(2)) + '-1' AS Date)
           ELSE StartDate
       END AS StartDate,
       CASE
           WHEN DatePart(MONTH, EndDate) > DATEPART(MONTH,@eDate) THEN @eDate
           ELSE EndDate
       END AS EndDate
FROM cte

答案 3 :(得分:1)

在这种情况下使用数字/日期/计数表是非常聪明的。在许多情况下,这样的桌子非常漂亮!

this answer中,我展示了如何创建和填充此类表格的方法。

创建此表后,查询就像:

一样简单
SELECT n.CalendarDate AS StartOfWeek
      ,DATEADD(DAY,6,n.CalendarDate) AS EndOfWeek
FROM dbo.RunningNumbers AS n
WHERE n.CalendarDate>={d'2017-01-01'} AND n.CalendarDate<{d'2017-02-01'}
  AND n.CalendarWeekDay=1;

提示这样的表可以很容易地扩展,只需通过手动将一些值添加到额外的列中来计算信息(例如,holydays, free-of-work 天)。 ..)

答案 4 :(得分:1)

如果您只想让一个函数返回一个月的一个月,那么这可以达到您想要的效果:

create function dbo.udf_weeks_of_month (@fromdate date) 
returns table as return (
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
)
select 
    WeekOfMonth = row_number() over (order by datepart(week,DateValue))
  , Week        = datepart(week,DateValue)
  , WeekStart   = min(DateValue)
  , WeekEnd     = max(DateValue)
from dates
group by datepart(week,DateValue)
);

并像这样调用它:

set datefirst 1;
select * from dbo.udf_weeks_of_month('20170101');

返回:

+-------------+------+------------+------------+
| WeekOfMonth | Week | WeekStart  |  WeekEnd   |
+-------------+------+------------+------------+
|           1 |    1 | 2017-01-01 | 2017-01-01 |
|           2 |    2 | 2017-01-02 | 2017-01-08 |
|           3 |    3 | 2017-01-09 | 2017-01-15 |
|           4 |    4 | 2017-01-16 | 2017-01-22 |
|           5 |    5 | 2017-01-23 | 2017-01-29 |
|           6 |    6 | 2017-01-30 | 2017-01-31 |
+-------------+------+------------+------------+

和这个电话:

select * from dbo.udf_weeks_of_month('february 2017');

返回:

+-------------+------+------------+------------+
| WeekOfMonth | Week | WeekStart  |  WeekEnd   |
+-------------+------+------------+------------+
|           1 |    6 | 2017-02-01 | 2017-02-05 |
|           2 |    7 | 2017-02-06 | 2017-02-12 |
|           3 |    8 | 2017-02-13 | 2017-02-19 |
|           4 |    9 | 2017-02-20 | 2017-02-26 |
|           5 |   10 | 2017-02-27 | 2017-02-28 |
+-------------+------+------------+------------+

rextester演示:http://rextester.com/VKPQU7936(注意:rextester重新格式化日期)

答案 5 :(得分:1)

这个主题有很多变化。这个比其他答案略短。

declare @dt date = {fn current_date()};
declare @start_of_year date = datefromparts(year(@dt), 1, 1);

with digits(d) as (
    select 0 union all select 1 union all select 2 union all select 3 union all
    select 4 union all select 5 union all select 6 union all select 7
), wks as (
    select
        dateadd(week, d1.d * 8 + d0.d, dateadd(day, 1-datepart(weekday, @start_of_year), @start_of_year)) as week_start,
        d1.d * 8 + d0.d as wk
    from digits as d0 cross join digits as d1
)
select
    case when year(week_start) < year(@dt)
        then @start_of_year else week_start end as week_start,
    case when year(dateadd(day, 6, week_start)) > year(@dt)
        then datefromparts(year(@dt), 12, 31) else dateadd(day, 6, week_start) end as week_end
from wks
where wk between 0 and 53 and year(week_start) = year(@dt)
order by week_start;