在我的日期维度 Table 中创建一个列的 SQL 语法是什么,它将日期分组到这个特定的周分组中?

What is the SQL syntax to create a column in my Date Dimension Table that will group the dates into this specific week grouping?

我正在使用 SQL Server 2014,我有一个日期维度 table(称为 DateDimension),其中一列是日期列(称为日期)。 table 列出从 2000-01-01 到 2017-12-31

的所有日期

从 DateDimension 中提取日期列 Table:

  2000-01-01 00:00:00.000
  2000-01-02 00:00:00.000
  .......................
  2017-12-31 00:00:00.000

我需要一个新列(比如 "Week Group"),其中 table 将使用以下逻辑对上述日期进行分组:

一周从星期一开始,到星期日结束。 因此,对于 2000 年 1 月 3 日(星期一)和 2000 年 1 月 9 日(星期日)之间的日期,新列将列出 "Wk 03-09 January 2015",依此类推日期维度中的剩余日期 Table.

实现这个的 T-SQL 代码是什么?

我假设你的 @@datefirst 对应星期天。而且我还假设文本的年月部分对应于一周的开始日而不是结束日。

您可以在 update 中使用第一个表达式,甚至可以将其用作计算列、函数或视图。由于区域设置,我不记得哪些日期函数存在确定性问题,因此可能存在一些限制。

concat(
'Wk ',
right('0' + datename(day, dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date")), 2),
'-',
right('0' + datename(day, dateadd(day, -((datepart(weekday, "Date") + 5) % 7)+6, "Date")),2),
' ',
datename(month, dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date")),
' ',
datename(year, dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date"))
)

由于计算中涉及两个日期,因此您无法轻松使用 format() 函数。这是完成同样事情的 two-step update

update DateDimension
set WeekGroup =
    format(
        dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date"),
        'Wk dd-XX MMMM yyyy' /* leave a placeholder */
    );

update DateDimension
set WeekGroup =
    replace(
        WeekGroup,
        'XX',
        format(
            dateadd(day, -((datepart(weekday, "Date") + 5) % 7) + 6, "Date"),
            'dd'
        )
    );

如果您喜欢嵌套表达式,当然可以一步完成:

update DateDimension
set WeekGroup =
    replace(
        format(
            dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date"),
            'Wk dd-XX MMMM yyyy' /* leave a placeholder */
        ),
        'XX',
        format(
            dateadd(day, -((datepart(weekday, "Date") + 5) % 7) + 6, "Date"),
            'dd'
        )
    );

数学真的没那么复杂:

要找到每个日期的 "week" 开始时间,我们要确定自上周一以来的天数。星期一被算作第 2 周的第 2 天(当 @@datefirst 设置为星期日时)所以我们想从 "regular" 工作日编号中减去两个并让它绕到前一周。为避免 mod 元算术中出现负数,只需加 5(与 -2 mod 7 等价)。重复使用相同的表达式来计算所有不同的日期部分。

编辑:在评论中,您已经暗示您确实需要为跨越一个月(也可能包括年)的几周使用稍微不同的格式。

这可以用 case 表达式处理。希望您已经了解了总体思路,并且可以看到在何处对您希望在两种情况下应用的格式进行调整。

update DateDimension
set WeekGroup =
    case
        when month(dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date")) =
             month(dateadd(day, -((datepart(weekday, "Date") + 5) % 7) + 6, "Date"))
        then
            replace(
                format(
                    dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date"),
                    'Wk dd-XX MMMM yyyy' /* leave a placeholder */
                ),
                'XX',
                format(
                    dateadd(day, -((datepart(weekday, "Date") + 5) % 7) + 6, "Date"),
                    'dd'
                )
            )
        else
            concat(
                format(
                    dateadd(day, -((datepart(weekday, "Date") + 5) % 7), "Date"),
                    'Wk dd MMMM yyyy-'
                    ),
                format(
                    dateadd(day, -((datepart(weekday, "Date") + 5) % 7) + 6, "Date"),
                    'dd MMMM yyyy'
                )
            )
    end;