SQL Server – получить первое свидание за неделю по номеру недели?
-
29-09-2020 - |
Вопрос
У меня есть запрос (для использования в bug tracker.net), который подсчитывает количество ошибок по неделям по статусу.Но запрос возвращает номер недели, а мне действительно нужен первый день недели.
select datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date)))
as [week], bg_status , st_name as [status], count(*) as [count]
from bugs inner join statuses on bg_status = st_id
group by datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date))),
bg_status, st_name
order by [week], bg_status
Часть, которая получает номер недели,
datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date))) as [week]
Он возвращает этот вывод:
week bg_status status count
----------- ----------- --------------------------------------------- ------
22 1 new 1
22 5 closed 32
Но лучше было бы указать первую дату каждой недели, например, 01.01.2010, затем 01.08.2010 и т. д.
Вопрос не является дубликатом Как получить «дату начала недели» и «дату окончания недели» из номера недели в SQL Server? (в ответе говорится, как начать неделю с даты, а не с номера недели)
Не дубликат Рассчитать дату по номеру недели (вопрос требует С#)
Не дубликат Получить первую дату недели из указанной даты (вопрос требует JavaScript)
Я искал, но не смог найти ответ на этот вопрос для SQL Server (2010, если это имеет значение)
Решение
Если подумать об этом правильно, то ответ на СО 1267126 можно применить к вашей проблеме.
Каждая дата сообщения об ошибке, указанная в группе, соответствует одной и той же неделе.Поэтому по определению каждая из этих дат ошибок также должна соответствовать одному и тому же началу недели.Итак, вы запускаете расчет «начала недели с заданной даты» по датам отчета об ошибке, а также вычисление номера недели и группируете их по обоим (довольно ужасным) выражениям, и в конечном итоге получаете ответ, который вы ищете.
SELECT DATEPART(wk, DATEADD(day, 0, DATEDIFF(d, 0, bg_reported_date))) [week],
DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1), bg_reported_date)
AS [weekstart], bg_status, st_name AS [status], COUNT(*) AS [count]
FROM bugs INNER JOIN statuses ON bg_status = st_id
GROUP BY DATEPART(wk, DATEADD(day, 0, DATEDIFF(day, 0, bg_reported_date))),
DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1), bg_reported_date),
bg_status, st_name
ORDER BY [week], bg_status
С bg_reported_date
это DATETIME (см. комментарий;он включает в себя компонент времени), необходимо привести его к DATE перед определением начала недели (но выражение номера недели не требует приведения, а часть выражения начала недели «день недели» не требует тоже нужен актерский состав):
SELECT DATEPART(wk, DATEADD(day, 0, DATEDIFF(d, 0, bg_reported_date))) [week],
DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1),
CAST(bg_reported_date AS DATE)) AS [weekstart],
bg_status, st_name AS [status], COUNT(*) AS [count]
FROM bugs INNER JOIN statuses ON bg_status = st_id
GROUP BY DATEPART(wk, DATEADD(day, 0, DATEDIFF(day, 0, bg_reported_date))),
DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1),
CAST(bg_reported_date AS DATE),
bg_status, st_name
ORDER BY [week], bg_status
Примечание:Непроверенный код!
Другие советы
Я понимаю, что это очень старая тема, но «получить первое свидание через неделю, учитывая номер недели», именно то, что я хотел сделать, и у меня нет фактической даты для работы, поэтому принятый ответ будетне работать для меня.Я думал, что я опубликую свое решение для потомства.Обратите внимание, что я подозреваю, что другие настройки культуры могут нарушить это, поэтому проверьте перед использованием.
Мой ответ построен начиная с Это One.
Давайте предположим, что вы знаете номер недели и год, и вы хотите получить начальные и конец даты на эту неделю этого года.Вот что у меня есть:
--These 2 "declared" variables would be passed in somehow
declare @WeekNumber int = DATEPART(wk, GETDATE())
declare @ForYear int = YEAR(GETDATE())-1
--Since we don't have a raw date to work with, I figured I could just start with
--Jan 1 of that year. I'll store that date in a cte here, but if you are doing this
--in a stored proc or function, it would make much more sense to use another @variable
;with x as
(
--this method works in SQL 2008:
SELECT CONVERT(DateTime, ('1/1/' + CONVERT(varchar, @ForYear))) as Jan1ForSelectedYear
--If you are using 2014 or higher, you can use this instead:
--DATETIME2FROMPARTS(@ForYear, 1, 1, 0,0,0,0,0)
)
--Now that we have a date to work with, we'll just add the number of weeks to that date
--That will bring us to the right week number of the given year.
--Once we have THAT date, we can get the beginning and ending of that week
--Sorry to make you scroll, but I think this is easier to see what is going on this way
SELECT CONVERT(varchar(50), DateAdd(wk, (@WeekNumber - 1), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, x.Jan1ForSelectedYear) - 6, x.Jan1ForSelectedYear))), 101) as FirstDayOfWeekXForSelectedYear,
CONVERT(varchar(50), DateAdd(wk, (@WeekNumber - 1), (DATEADD(dd, @@DATEFIRST - DATEPART(dw, x.Jan1ForSelectedYear) , x.Jan1ForSelectedYear))), 101) as LastDayOfWeekXForSelectedYear
FROM x
.