【问题标题】:SQL Server - Get first date in a week, given the week number?SQL Server - 给定周数,获取一周内的第一个日期?
【发布时间】:2010-07-26 00:28:52
【问题描述】:

我有一个查询(用于 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,然后是 08-01-2010,等等

问题不是How do you get the "week start date" and "week end date" from week number in SQL Server? 的重复项(答案说如何从日期开始而不是从周数开始)

不是Calculate date from week number的重复项(问题要求c#)

不是 Get first date of week from provided date 的重复项(问题要求使用 javascript)

我进行了搜索,但找不到针对 SQL Server(2010 如果重要的话)回答的这个问题

【问题讨论】:

  • DateAdd(day, 0, DateDiff(day, 0, bg_reported_date)) 是做什么的?我怀疑它可以被简化。
  • @Gabe:我认为内部 DateDiff() 计算“日期 0”和错误报告日期之间的天数。然后,外部 DateAdd() 将该天数添加到“日期 0”,给出一个 DATE 值(或者,可能是一个具有 0 小时、0 分钟、0 秒的 DATETIME 值)。如果可以简化,我认为简化可能是CAST(bg_reported_date AS DATE),如“周开始”表达式中使用的那样。
  • 乔纳森:我就是这么想的,但你为什么要在调用DATEPART 时使用它是没有意义的。给定日期的所有时间都应始终返回相同的周数。

标签: sql-server tsql week-number bugtracker.net


【解决方案1】:

如果您以正确的方式思考它,SO 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

注意:未经测试的代码!

【讨论】:

  • 分组不正确,因为 bg_reported_date 包含时间。我会先看看当时间被删除时会发生什么。这会使该表达式变得更糟 - bg_reported_date 存在 3 次,因此必须将时间删除 3 次。
  • 很好,谢谢。它是一堆丑陋的 DATETHIS 和 DATETHAT 函数,但效果很好。
【解决方案2】:

我意识到这是一个非常古老的线程,但是“在一周内获得第一个约会,给定周数”正是我想要做的,我没有实际的工作日期,所以接受的答案是不适合我。我想我会为后代发布我的解决方案。请注意,我怀疑不同的文化设置可能会破坏这一点,因此请在使用前进行测试。

我的答案是从this一开始构建的。

假设您知道周数和年份,并且您想获取该周的开始日期和结束日期。这是我所拥有的:

--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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    相关资源
    最近更新 更多