Получите дату начала и дату окончания недели для каждой недели

#sql #sql-server #tsql

Вопрос:

Это мой код

 declare @startdate date='2021-01-01'
declare @enddate date='2021-12-31'
declare @week_end_date date

while (@startdate <= @enddate)
begin
    if (datepart(week, @startdate) = 1)
        select '01-01-2021'
    else
        set @startdate = DATEADD(day,1-datepart(dw,@startdate),@startdate)

    select @startdate week_start_date

    if (datepart(week, @startdate) = 53)
        select '2021-12-31' 
    else
        set @week_end_date = dateadd(day, 7 - datepart(dw, @startdate), @startdate)

    select @week_end_date week_end_date

    set @startdate = dateadd(week, 1, @startdate)   
end
 

Я хочу добиться следующего результата

 week_start date             week_end_date
-----------------------------------------
2021-01-01                   2021-01-02
2021-01-03                   2021-01-09
2021-01-10                   2021-01-16
.
.
.
.
.
.
2021-12-26                  2021-12-31
.
.
 

Я пытаюсь получить start_date и end_date недели за каждую неделю, но я хочу, чтобы дата начала первой недели была 2020-01-01 датой окончания последней недели 2020-12-31

В обоих случаях else работает.

Комментарии:

1. Я бы предложил использовать для этого таблицу подсчетов или чисел вместо циклов. Я не совсем понимаю желаемый результат. Не могли бы вы попытаться это объяснить?

2. @Sean OP хочет создать список недель (с воскресенья по субботу), охватывающих год. Но неполные недели должны быть сокращены, чтобы соответствовать календарному году.

3. почему бы просто не использовать GREATEST и LEAST не препятствовать тому, чтобы начальные и конечные дни выходили за рамки ваших переменных начала/конца?

4. Что производит ваш код? Как это неправильно?

5. для определенного диапазона дат, например, с 2021-01-01 по 2021-12-31, мне нужна дата начала каждой недели вместе с датой окончания каждой недели, но для первой недели мне нужен день начала недели как 2021-01-01, а дата окончания недели как 2021-12-31, если указан вышеуказанный диапазон, мне нужна обычная дата начала недели и дата окончания недели.

Ответ №1:

Я предполагаю, что вам действительно нужно охватить только полный календарный год. Первые два CTE просто создают «таблицу чисел». При необходимости вы можете подключить замену. Я также предполагаю datefirst , что значение 7.

 with d as (
    select n from (values (0), (1), (2), (3), (4), (5), (6), (7)) t(n)
), w as (
    select d0.n   d1.n * 8 as offset from d as d0 cross join d as d1
), weeks as (
    select
        offset   1 as weeknum,
        dateadd(week, offset, basedate) as weekstart,
        dateadd(day, 6, dateadd(week, offset, basedate)) as weekend
    from w cross apply (
        select dateadd(day, 1 - datepart(weekday, @startdate), @startdate)
    ) as v(basedate)
)
select
    weeknum,
    case when weekstart < @startdate then @startdate else weekstart end,
    case when weekend   > @enddate   then @enddate   else weekend end
from weeks
where weekstart <= @enddate;
 

https://dbfiddle.uk/?rdbms=sqlserver_2014amp;fiddle=5f900ecd26b92e4a112f191730958cae

Комментарии:

1. @Питер, хорошая мысль. Я поместил слишком много строк в d выражение. Это приводит к некоторым дубликатам.

2. Это действительно близко. Даты начала и окончания недели отличаются от того, что хочет ОП. В противном случае это победитель.

3. @Шон, я думаю, они совпадают. Возможно ли, что ваша дата первого не 1?

4. Бваааааааааааа!!!! Да, на днях я работал над некоторыми забавными вещами с моей фиктивной базой данных. Мое первое свидание было 7 лет назад!!! Еще одно доказательство того, почему в реальной среде всегда важно установить это в своих сценариях. 😀

5. Я неправильно истолковал кое-что в приведенном выше сценарии ОП. Таким образом, OP, по-видимому, использует datefirst 7. Я соответствующим образом приспособился.

Ответ №2:

Я подозреваю, что вы хотите что-то подобное, что позволит сохранить все даты в указанном диапазоне. Жесткая привязка к одному году, который почти закончился, не является хорошим долгосрочным планом.

В Azure SQL вы можете сделать это

 declare @startdate date='2021-01-01'
declare @enddate date='2021-12-31'
declare @curdate date=@startdate
declare @week_end_date date

while(@curdate<=@enddate)
begin
    set @curdate= DATEADD(day,1-datepart(dw,@curdate),@curdate)
    select GREATEST(@startdate,@curdate) week_start_date

    set @week_end_date=dateadd(day,7-datepart(dw,@curdate),@curdate)
    select LEAST(@enddate,@week_end_date) week_end_date

    set @curdate= dateadd(week,1,@curdate)    
end
 

Для SQL Server 2019 НАИБОЛЬШИЕ/НАИМЕНЬШИЕ значения пока недоступны.

     declare @startdate date='2021-01-01'
    declare @enddate date='2021-12-31'
    declare @curdate date=@startdate
    declare @week_end_date date
    
    while(@curdate<=@enddate)
    begin
        set @curdate= DATEADD(day,1-datepart(dw,@curdate),@curdate)
        select IIF(@startdate>@curdate,@startdate,@curdate) week_start_date
    
        set @week_end_date=dateadd(day,7-datepart(dw,@curdate),@curdate)
        select IIF(@week_end_date > @enddate,@enddate, @week_end_date) week_end_date
    
        set @curdate= dateadd(week,1,@curdate)    
    end
 

Комментарии:

1. я пытался, но я не могу использовать наименьшее и наибольшее в sql server

2. Это код MySQL, но вопрос четко обозначен с помощью sql server.

3. Это действительно в Transact-SQL, но, по-видимому, только в Azure, извините

4. Не поклонник зацикливания, но это возвращает правильную информацию.

5. @mamta Как я прокомментировал по крайней мере один из ваших других подобных вопросов сегодня, получите таблицу календаря . Определите эти недели ровно один раз, сохраните их где-нибудь, и это избавит всех от необходимости в течение всего дня разбирать все ваши крайние случаи.