2017-02-13 40 views
1

ため、私たちは以下のように示すか月の出力のための週の開始日と終了日を取得する必要があります:開始日と終了日の月

Week# StartDate EndDate 
Week 1 2017-03-01 2017-03-04 
Week 2 2017-03-05 2017-03-11 
Week 3 2017-03-12 2017-03-18 
Week 4 2017-03-19 2017-03-25 
Week 5 2017-03-26 2017-03-31 

答えて

2

これは動作するはずです:

declare @first_day_of_month date = '20170301' 
    declare @days_in_month int = datediff(day, @first_day_of_month, dateadd(month, 1, @first_day_of_month)) 

    ;with x as (
     select datepart(week, dateadd(day, n-1, @first_day_of_month))+1 wk, dateadd(day, n-1, @first_day_of_month) dy 
     from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10), (11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30), (31)) as numbers(n) 
     where n <= @days_in_month 
    ) 
    select wk - datepart(week, @first_day_of_month) as [Week#], min(dy) as StartDate, max(dy) as EndDate 
    from x 
    group by wk 
    order by wk 

データベースにNumbersテーブルがある場合は、valuesを取り除くことができます。

これについてどのように
+0

ヶ月が31日より短い場合、これは先週の月の終了日のうちを与えます。 http://rextester.com/DIJ37633 – SqlZim

+0

@SqlZim有効なポイントが編集されました。 – dean

0

Declare @StartDate Date = '2017-03-01' 
;With Nums 
AS 
(
    SELECT * 
    FROM (VALUES (0),(1),(2),(3),(4)) Nums(n) 
), 
StartDate 
AS 
(
    SELECT @StartDate As StartDate, DatePart(dw,@StartDate) As DayWeekNumber 
) 
SELECT DATEADD(Week, n, CASE WHEN n = 0 THEN StartDate ELSE DATEADD(Day, DayWeekNumber * -1 + 1, StartDate) END) As StartDate, 
     CASE WHEN DATEPART(Month, DATEADD(Week, n+1, DATEADD(Day, DayWeekNumber * -1 , StartDate))) = DATEPART(Month, @StartDate) 
      THEN DATEADD(Week, n+1, DATEADD(Day, DayWeekNumber * -1 , StartDate)) 
      ELSE EOMONTH(@StartDate) END As EndDate 
FROM Nums 
CROSS JOIN StartDate 
0

オプション1:非UDFのバージョン

Declare @Date1 date = '2017-03-01' 
Declare @Date2 date = '2017-03-31' 

Select [Week#] 
     ,StartDate = min(D) 
     ,EndDate = max(D) 
From (
     Select *,[Week#] = concat('Week ',Dense_Rank() over (Partition By Year(D),Month(D) Order By DatePart(WK,D))) 
     From (Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From master..spt_values) A1 
     ) A 
Group By [Week#],Year(D),Month(D) 
Order By 2 

オプション2:TFVバージョン

私はしばしばにTVFを使用します動的な日付/時間範囲を作成します。タリー/カレンダーテーブルも同様ですが、UDFにはいくつかの動的オプションがあります。あなたはこのだろう、日付範囲は、DATEPARTおよびインクリメント

Declare @Date1 date = '2017-03-01' 
Declare @Date2 date = '2017-03-31' 

Select [Week#] 
     ,StartDate = min(RetVal) 
     ,EndDate = max(RetVal) 
From (
     Select *,[Week#] = concat('Week ',Dense_Rank() over (Partition By Year(RetVal),Month(RetVal) Order By DatePart(WK,RetVal))) 
      From [dbo].[udf-Range-Date](@Date1,@Date2,'DD',1) 
     ) A 
Group By [Week#],Year(RetVal),Month(RetVal) 
Order By 2 

はどちらも一回限りの使用のために

Week# StartDate EndDate 
Week 1 2017-03-01 2017-03-04 
Week 2 2017-03-05 2017-03-11 
Week 3 2017-03-12 2017-03-18 
Week 4 2017-03-19 2017-03-25 
Week 5 2017-03-26 2017-03-31 

UDFもし興味

CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int) 
Returns Table 
Return (
    with cte0(M) As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End), 
     cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
     cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h), 
     cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2) 

    Select RetSeq = N+1 
      ,RetVal = D 
    From cte3,cte0 
    Where D<[email protected] 
) 
/* 
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS 
Syntax: 
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/ 
0

を返す供給します仕事:

rextester:あなたは、必要に応じて参照することができ、カレンダーテーブルを持つようにしたい場合はhttp://rextester.com/WCMZRW61517

declare @FromDate date = '20170301'; 

with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)) 
, d as (
    select DateValue=convert(date,dateadd(day 
     , row_number() over (order by (select 1)) -1, @FromDate)) 
    from   n as deka 
     cross join n as hecto 
) 
select 
     [Week#] = dense_rank() over (
       partition by dateadd(month, datediff(month, 0, DateValue) , 0) 
       order by convert(tinyint,datepart(week,DateValue)) 
       ) 
    , StartDate = min(DateValue) 
    , EndDate = max(DateValue) 
from d 
where dateadd(month, datediff(month, 0, DateValue) , 0) = @FromDate 
group by 
    dateadd(month, datediff(month, 0, DateValue) , 0) 
    , convert(tinyint,datepart(week,DateValue)) 

は、このような何かが働くだろう:

if object_id('dbo.Calendar') is not null drop table dbo.Calendar; 
create table dbo.Calendar (
    [Date]   date  not null 
    , [Year]   smallint not null 
    , [Month]  tinyint not null 
    , MonthStart  date  not null 
    , MonthEnd  date  not null 
    , [Week]   tinyint not null 
    , MonthWeek  tinyint not null 
    , MonthWeekStart date  not null 
    , MonthWeekEnd date  not null 
    , constraint pk_Calendar primary key clustered (date) 
); 

declare @FromDate date = '20170101'; 
declare @ThruDate date = '20171231'; 

with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)) 
, d as (
    select 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  /* 2.73 years */ 
     cross join n as [tenK] /* 27.3 years */ 
     --cross join n as [hundredk] /* 273 years */ 
) 

insert into dbo.Calendar 
    ([Date], [Year], [Month],MonthStart, MonthEnd, [Week] 
     , MonthWeek, MonthWeekStart, MonthWeekEnd) 
    select top (datediff(day, @FromDate, @ThruDate)+1) 
     [Date]  = DateValue 
    , [Year]  = convert(smallint,datepart(year,DateValue)) 
    , [Month]  = convert(tinyint,datepart(month,DateValue)) 
    , MonthStart = dateadd(month, datediff(month, 0, DateValue) , 0) 
    , MonthEnd  = convert(date,dateadd(day,-1 
         ,dateadd(Month,datediff(Month,0,DateValue) +1,0))) 
    , [Week]  = convert(tinyint,datepart(week,DateValue)) 
    , MonthWeek  = dense_rank() over (
         partition by dateadd(month, datediff(month, 0, DateValue) , 0) 
         order by convert(tinyint,datepart(week,DateValue)) 
        ) 
    , MonthWeekStart = min(DateValue) over (
         partition by dateadd(month, datediff(month, 0, DateValue) , 0) 
            , convert(tinyint,datepart(week,DateValue)) 
         ) 
    , MonthWeekEnd = max(DateValue) over (
         partition by dateadd(month, datediff(month, 0, DateValue) , 0) 
            , convert(tinyint,datepart(week,DateValue)) 
         ) 

    from d 
    order by DateValue; 

select distinct 
     MonthWeek 
    , MonthWeekStart 
    , MonthWeekEnd 
from dbo.Calendar 
where MonthStart = '20170301' 

カレンダーと数字の表

関連する問題