3

テーブルに Start_date と End_date という 2 つの日付列があります。最初に、これら 2 つの日付の間に何週間あるかを調べて、データを分割する必要があります。

--たとえば、データが次のようになっている場合、

ID  Start_date  End_date   No_Of_Weeks
1   25-Apr-11   8-May-11     2
2   23-Apr-11   27-May-11    6

-- 次のような結果が必要です。

ID  Start_date       End_date

1       25-Apr-2011     01-May-2011
1       02-May-2011     08-May-2011  

2       23-Apr-2011     24-Apr-2011
2       25-Apr-2011     01-Apr-2011
2       02-May-2011     08-May-2011
2       09-May-2011     15-May-2011
2       16-May-2011     22-May-2011
2       23-May-2011     27-May-2011

クエリを手伝ってください。私の週の開始日は月曜日です。

4

9 に答える 9

1

アンビエントテストの設定

    declare @dt table (ID int,Start_date datetime,
                       End_date datetime,No_Of_Weeks int)

    insert into @dt (ID,Start_date,End_date,No_Of_Weeks)
    select 1,   '25-Apr-11',   '8-May-11',     2
    union all
    select 2,  '23-Apr-11' ,  '27-MAy-11' ,   6;

これを試して...

    with cte as (select d.ID
                       ,d.Start_date
                       ,(select MIN([end]) from (values(d.End_date),(DATEADD(day,-1,DATEADD(week,DATEDIFF(week,0,d.Start_date)+1,0))))V([end])) as End_date
                       ,d.End_date as end_of_period
                 from @dt d
                 union all select d.ID
                      ,DATEADD(day,1,d.End_date) as Start_date
                       , case when d.end_of_period < DATEADD(week,1,d.End_date) then d.end_of_period else DATEADD(week,1,d.End_date) end as End_date
                       ,d.end_of_period as end_of_period
                 from cte d
                 where end_of_period <> End_date
                )
    select ID
          ,cast(Start_date as DATE) Start_date
          ,cast(End_date as date) End_date 
    from cte
    order by cte.ID,cte.Start_date
    option(maxrecursion 0)

達成された結果セット...

    ID  Start_date  End_date
    1   2011-04-25  2011-05-01
    1   2011-05-02  2011-05-08
    2   2011-04-23  2011-04-24
    2   2011-04-30  2011-05-01
    2   2011-05-07  2011-05-08
    2   2011-05-14  2011-05-15
    2   2011-05-21  2011-05-22
    2   2011-05-28  2011-05-27
于 2013-02-18T18:00:50.863 に答える
1

このクエリを試してみてください、うまくいくことを願っています

週が日曜日に始まる場合は、以下を使用してください

set datefirst 7

declare @FromDate datetime = '20130110'
declare @ToDate datetime = '20130206'

select datepart(week, @ToDate) - datepart(week, @FromDate) + 1

週が月曜日に始まる場合は、以下を使用してください

set datefirst 1

declare @FromDate datetime = '20100201'
declare @ToDate datetime = '20100228'

select datepart(week, @ToDate) - datepart(week, @FromDate) + 1

注:開始日が異なるため、どちらのクエリでも異なる結果が得られます。

于 2013-02-20T11:37:42.607 に答える
1

最後の理解によると、これは機能します:

with demo_cte as 
(select id,
 start_date,
 dateadd(day,6,DATEADD(wk, DATEDIFF(wk,0,start_date), 0)) end_date,
 end_date last_end_date,
 no_of_weeks no_of_weeks from demo


 union all

 select id,dateadd(day,1,end_date),
   dateadd(day,7,end_date),

 last_end_date
 ,no_of_weeks-1 from demo_cte

 where no_of_weeks-1>0)

 select id, start_date,
case
when end_date<=last_end_date then end_date
else
last_end_date
end
end_date
from demo_cte order by id,no_of_weeks desc

SQLフィドル

そして、週数が利用できない場合は、これを使用してください:

with demo_cte as 
(select id,
 start_date,
 dateadd(day,6,DATEADD(wk, DATEDIFF(wk,0,start_date), 0)) end_date,
 end_date last_end_date
 --,no_of_weeks no_of_weeks
 from demo


 union all

 select id,dateadd(day,1,end_date),
   dateadd(day,7,end_date),

 last_end_date
 --,no_of_weeks-1 
 from demo_cte

 where --no_of_weeks-1>0
 dateadd(day,7,end_date)<=last_end_date 
)

 select id, start_date,
case
when end_date<=last_end_date then end_date
else
last_end_date
end
end_date
from demo_cte order by id,start_date
--,no_of_weeks desc
于 2013-01-30T12:22:46.577 に答える
1

週を定義するカレンダー テーブルを使用して、それをデータに結合できます。

次のSQLフィドルを作成しました。

CREATE TABLE Calendar_Weeks (
  week_start_date date,
  week_end_date date )

CREATE TABLE Sample_Data (
  id int,
  start_date date,
  end_date date )

INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-04-18','2011-04-24')
INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-04-25','2011-05-01')
INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-05-02','2011-05-08')
INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-05-09','2011-05-15')
INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-05-16','2011-05-22')
INSERT Calendar_Weeks (week_start_date, week_end_date) VALUES ('2011-05-23','2011-05-29')

INSERT Sample_Data (id, start_date, end_date) VALUES (1, '2011-04-25','2011-05-08')
INSERT Sample_Data (id, start_date, end_date) VALUES (2, '2011-04-23','2011-05-27')


SELECT id, week_start_date, week_end_date
FROM Sample_Data CROSS JOIN Calendar_Weeks
WHERE week_start_date BETWEEN start_date AND end_date
UNION
SELECT id, week_start_date, week_end_date
FROM Sample_Data CROSS JOIN Calendar_Weeks
WHERE week_end_date BETWEEN start_date AND end_date

UNIONセットの最初または最後に行を含めるには、クエリが少しハックに感じられることを認めなければならないので、Ravi Singh のソリューションを使用することをお勧めします。

必要に応じて次のものも使用INNER JOINできます。

SELECT id, week_start_date, week_end_date
FROM Sample_Data INNER JOIN Calendar_Weeks
ON week_start_date BETWEEN start_date AND end_date
UNION
SELECT id, week_start_date, week_end_date
FROM Sample_Data INNER JOIN Calendar_Weeks
ON week_end_date BETWEEN start_date AND end_date
于 2013-01-30T13:33:27.520 に答える
0

DATEDIFF関数の使用を検討する必要があります。

質問の後半で何を求めているのかわかりませんが、日付の違いがわかったら、DATEDIFF の結果に CASE を使用してみてください。

于 2013-01-30T10:36:14.047 に答える
0
set datefirst 1
GO

with cte as (
    select ID, Start_date, End_date, Start_date as Week_Start_Date, (case when datepart(weekday, Start_date) = 7 then Start_Date else cast(null as datetime) end) as Week_End_Date, datepart(weekday, Start_date) as start_weekday, cast(0 as int) as week_id
    from (
        values (1, cast('25-Apr-2011' as datetime), cast('8-May-2011' as datetime)),
                (2, cast('23-Apr-2011' as datetime), cast('27-May-2011' as datetime))
    ) t(ID, Start_date, End_date)

    union all

    select ID, Start_date, End_date, dateadd(day, 1, Week_Start_date) as Week_Start_Date, (case when start_weekday + 1 = 7 then dateadd(day, 1, Week_Start_date) else null end) as Week_End_date, (case when start_weekday = 7 then 1 else start_weekday + 1 end) as start_weekday, (case when start_weekday = 7 then week_id + 1 else week_id end) as week_id
    from cte
    where Week_Start_Date != End_date
)
select ID, min(Week_Start_Date), isnull(max(Week_End_Date), max(End_Date))
from cte
group by ID, Week_id
order by ID, 2
option (maxrecursion 0)

週数を取得したい場合は、cte の後の select を次のように変更できます。

select ID, Start_date, End_date, count(distinct week_id) as Number_Of_Weeks
from cte
group by ID, Start_date, End_date
option (maxrecursion 0)

明らかに、使用されるデータを変更するには、values() が使用されている cte のアンカー (最初の部分) が変更されます。

これは、月曜日を週の最初の日として使用します。別の日にset datefirst、上部のステートメントを変更してください - -- http://msdn.microsoft.com/en-gb/library/ms181598.aspx

于 2013-02-24T08:57:45.047 に答える
0

datepart関数を使用して、週が月曜日に始まるという事実を説明するソリューションを次に示します。

with demo_normalized as 
(
 select id,
  start_date,
  (datepart(dw,start_date) + 5) % 7 as test,
  dateadd(d,
       0 - ((datepart(dw,start_date) + 5) % 7),
       start_date
  ) as start_date_firstofweek,
  dateadd(d,
       6 - ((datepart(dw,start_date) + 5) % 7),
       start_date
  ) as start_date_lastofweek,
  end_date,
  dateadd(d,
       0 - ((datepart(dw,end_date) + 5) % 7),
       end_date
  ) as end_date_firstofweek,
  dateadd(d,
       6 - ((datepart(dw,end_date) + 5) % 7),
       end_date
  ) as end_date_lastofweek,
  datediff(week,
      dateadd(d,
          0 - ((datepart(dw,start_date) + 5) % 7),
          start_date
      ),
      dateadd(d,
          6 - ((datepart(dw,end_date) + 5) % 7),
          end_date
      )
  ) as no_of_weeks
 from demo
),
demo_cte as
(
  select
    id,
    dateadd(day,7,start_date_firstofweek) as start_date,
    dateadd(day,7,start_date_lastofweek) as end_date,
    end_date_firstofweek,
    no_of_weeks   
  from demo_normalized
  where no_of_weeks >= 3
  UNION ALL select
    id,
    dateadd(day,7,start_date) as start_date,
    dateadd(day,7,end_date) as end_date,
    end_date_firstofweek,
    no_of_weeks   
  from demo_cte
  where
    (dateadd(day,8,start_date) < end_date_firstofweek)
),
demo_union as
(
  select id, start_date, end_date, no_of_weeks from demo_normalized where no_of_weeks = 1
  union all
  select id, start_date, start_date_lastofweek as end_date, no_of_weeks
  from demo_normalized where no_of_weeks >= 2  
  union all
  select id, start_date, end_date, no_of_weeks from demo_cte
  union all
  select id, end_date_firstofweek as start_date, end_date, no_of_weeks
  from demo_normalized where no_of_weeks >= 2  
)
select
  d0.id,
 d0.no_of_weeks,
 convert(varchar, d0.start_date, 106) as start_date,
 convert(varchar, d0.end_date, 106) as end_date
from demo_union d0
order by d0.id, d0.start_date

EDIT(間の週にCTEを追加):これはsqlfiddle へのリンクです

: このソリューションには追加の DDL は必要ありません。追加のエンティティを作成して維持する必要はありません。つまり、カレンダーを再発明するわけではありません。すべてのカレンダー ロジックはクエリに含まれています。

于 2013-02-20T16:51:55.487 に答える
0

楽しみ!

WITH D AS (
SELECT id
     , start_date
     , end_date
     , start_date AS WEEK_START
     , start_date + 7 - DATEPART(weekday,start_date) + 1
       AS week_end
 FROM DATA
), W AS (
SELECT id
     , start_date
     , end_date
     , WEEK_START
     , WEEK_END
 FROM D
UNION ALL
SELECT id
     , start_date
     , end_date
     , WEEK_END + 1 AS WEEK_START
     , WEEK_END + 7 AS WEEK_END
 FROM W
WHERE WEEK_END < END_DATE
)
SELECT ID
     , WEEK_START AS START_DATE
     , WEEK_END AS END_DATE
 FROM W
 ORDER BY 1, 2;
于 2013-02-24T17:19:29.340 に答える
0

Jeff Moden がThe "Numbers" or "Tally" Table: What is what it is and how it replaces a loop (required login) で提案するタイプと同様の日付集計テーブルを使用する必要があります。

Tally テーブルは、0 または 1 (私の場合は 1 から始まります) から始まり、いくつかの数字まで、非常に適切にインデックス付けされた連続番号の単一の列を持つテーブルにすぎません。Tally テーブルの最大数は、恣意的な選択であってはなりません。それは、あなたがそれを何に使うと思うかに基づいているべきです。私は VARCHAR(8000) を私のものと分割したので、少なくとも 8000 の数字でなければなりません。時折 30 年の日付を生成する必要があるため、生産集計テーブルのほとんどを 11,000 以上に保ちます。これは 365.25 日 x 30 年を超えます。

私は Tony の SQL Fiddler から始めましDateInformationたが、もう少し一般的なテーブルを実装しました。これは、再利用できるものになる可能性があります。

--Build Test Data, For production set the date 
--range large enough to handle all cases.
CREATE TABLE DateInformation (
    [Date] date,
    WeekDayNumber int,
)

--From Tony
CREATE TABLE Sample_Data (
id int,
start_date date,
end_date date )

DECLARE @CurrentDate Date = '2010-12-27'

While @CurrentDate < '2014-12-31'
BEGIN
    INSERT DateInformation VALUES (@CurrentDate,DatePart(dw,@CurrentDate))
    SET @CurrentDate = DATEADD(DAY,1,@CurrentDate)
END

--From Tony
INSERT Sample_Data VALUES (1, '2011-04-25','2011-05-08')
INSERT Sample_Data VALUES (2, '2011-04-23','2011-05-27')

CTE を使用してサンプル データをDateInformationテーブルに結合するソリューションを次に示します。

--Solution using CTE
with Week (WeekStart,WeekEnd) as
(
  select d.Date 
        ,dateadd(day,6,d.date) as WeekEnd
  from DateInformation d
  where d.WeekDayNumber = 2
)

select 
  s.ID
  ,case when s.Start_date > w.WeekStart then s.Start_Date 
    else w.WeekStart end as Start_Date
  ,case when s.End_Date < w.WeekEnd then s.End_Date
    else w.WeekEnd end as End_Date
from Sample_Data s
join Week w on w.WeekStart > dateadd(day,-6,s.start_date)
            and w.WeekEnd <= dateadd(day,6,s.end_date);

SQL Fiddle で解決策を参照してください

于 2013-02-23T07:07:56.013 に答える