【问题标题】:Get correct week number for december 31st获取 12 月 31 日的正确周数
【发布时间】:2019-01-02 14:05:00
【问题描述】:

在 SQL Server 中,我试图获取给定日期的周数(带有年份),欧洲风格,所以我使用 DATEPARTISO_WEEK 参数:

SELECT CAST(DATEPART(year, myDate) AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, myDate) AS VARCHAR), 2);

这很好用,除了 2018 年 12 月 31 日,它是 2019 年的第一周,但由于我在一年和一周分别使用 DATEPART,这显然行不通。以下是 myDate 为 31-12-2018 的示例:

SELECT CAST(DATEPART(year, '31-12-2018') AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, '31-12-2018') AS VARCHAR), 2);

上述查询返回“201801”。

有没有办法简单地获得 2018 年 12 月 31 日的 201901,而无需明确测试该日期?

【问题讨论】:

标签: sql-server tsql


【解决方案1】:

查看可能的重复引用并稍微整理一下:

declare @d datetime = '2018-12-31';
select cast(year(dateadd(day, 26 - datepart(ISO_WEEK, @d), @d)) as varchar(4)) + right(('0' + cast(datepart(ISO_WEEK, @d) as varchar(2))), 2)

结果为@​​987654322@。

测试代码:

select cast(ds.d as date) as 'date', cast(year(dateadd(day, 26 - datepart(ISO_WEEK, ds.d), ds.d)) as varchar(4)) + right(('0' + cast(datepart(ISO_WEEK, ds.d) as varchar(2))), 2) as "IsoWeek"
from (
    select dateadd(day, x.num, '2018-12-30') as d
    from (
        select h.num + d.num + s.num as num
        from (
            select 0 num union select 100 num union select 200 num union select 300 num
        ) h
        cross join (
            select 0 num union select 10 num union select 20 num union select 30 num
        ) d
        cross join (
            select 0 num union select 1 num union select 2 union select 3 num
        ) s
    ) x    
) ds
order by ds.d

导致:

日期等周 2018-12-30 201852 2018-12-31 201901 2019-01-01 201901 2019-01-02 201901 2019-01-09 201902 2019-01-10 201902 2019-01-11 201902 2019-01-12 201902 2019-01-19 201903 2019-01-20 201903 2019-01-21 201904 2019-01-22 201904 2019-01-29 201905 2019-01-30 201905 2019-01-31 201905 2019-02-01 201905 2019-04-09 201915 2019-04-10 201915 2019-04-11 201915 2019-04-12 201915 2019-04-19 201916 2019-04-20 201916 2019-04-21 201916 2019-04-22 201917 2019-04-29 201918 2019-04-30 201918 2019-05-01 201918 2019-05-02 201918 2019-05-09 201919 2019-05-10 201919 2019-05-11 201919 2019-05-12 201919 2019-07-18 201929 2019-07-19 201929 2019-07-20 201929 2019-07-21 201929 2019-07-28 201930 2019-07-29 201931 2019-07-30 201931 2019-07-31 201931 2019-08-07 201932 2019-08-08 201932 2019-08-09 201932 2019-08-10 201932 2019-08-17 201933 2019-08-18 201933 2019-08-19 201934 2019-08-20 201934 2019-10-26 201943 2019-10-27 201943 2019-10-28 201944 2019-10-29 201944 2019-11-05 201945 2019-11-06 201945 2019-11-07 201945 2019-11-08 201945 2019-11-15 201946 2019-11-16 201946 2019-11-17 201946 2019-11-18 201947 2019-11-25 201948 2019-11-26 201948 2019-11-27 201948 2019-11-28 201948

【讨论】:

  • 效果很好!你能解释一下这是如何工作的吗?
  • @iMezouar 26 周数字的“魔法”是获得“iso 年”的算术技巧(在一张纸上算出来!)。剩下的只是字符串处理(例如right('0'+ number, 2) 只是零填充数字:当周大于9时会有一个三个字符的字符串。总结:分解子表达式子表达式。测试代码主要是生成通过生成一组数字然后将它们添加到基准日期来确定日期(主要是使用cross join :-) 的借口)。
  • 如果他没有机会告诉你它是如何工作的(26 - WeekNumber)如果 weekNumber 是 53 将是负数。在这种情况下,对于诸如 01/01/2027 之类的日期,天将减去 2026 年。对于 2026 年 12 月 31 日,也将减去 2026 年的年份。对于 2018 年 12 月 31 日,您最终将增加 27 天,使之成为 2018 年。看来您可以永远不要在错误的时间增加或减少太多的日子,进入错误的年份,这真的很巧妙。
  • @Richard,我的问题实际上是关于 Cato 优雅地解释的(26 周数)部分,我在原始查询中已经有了连接部分,并且交叉连接很清楚: ) 谢谢大家。
【解决方案2】:

问题是有一个特殊情况,即周数可能在一年中非常“早”,尽管它实际上是第 12 个月,因此很容易检查 12 月是否有一年的开始周,在这种情况下,只需在年份中添加一个,

DECLARE @mydate as datetime2 = '20270101';
SELECT CAST(DATEPART(year, @myDate) 
            + case when DATEPART(ISO_WEEK, @myDate) < 2 and month(@mydate) =12 then 
                                                      1 
                                                 else 
                                                       0 
                                                 end   

             + case when DATEPART(ISO_WEEK, @myDate) >10 and month(@mydate) =1 then 
                                                  -1 
                                             else 
                                                   0 
                                             end 
AS VARCHAR) 
              + RIGHT('0' + CAST(DATEPART(ISO_WEEK, @myDate) AS VARCHAR), 2);

我添加了对另一个答案中突出显示的 2027 年问题的更正。

【讨论】:

    【解决方案3】:

    检查以下查询,它使用一周的最后一天来获取年份值

    SELECT CAST(DATEPART(year, DATEADD(wk, 1, DATEADD(DAY, 0-DATEPART(WEEKDAY, '2018-12-31'), DATEDIFF(dd, 0, '2018-12-31')))) AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, '2018-12-31') AS VARCHAR), 2);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-24
      相关资源
      最近更新 更多