#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 Как я прокомментировал по крайней мере один из ваших других подобных вопросов сегодня, получите таблицу календаря . Определите эти недели ровно один раз, сохраните их где-нибудь, и это избавит всех от необходимости в течение всего дня разбирать все ваши крайние случаи.