我有一个数据 struct

StartTime EndTime BunchOfOtherColumns

我需要使用SELECT创建一个新列,其中添加了一个格式化的日期,该日期落入BiWeekly buckets(星期一-星期日).

例如,对于结果中的每一行,如果EndTime的日期在10月2日至10月15日之间,则新列将显示10/15/23.如果EndTime的日期在10月16日至10月29日之间,则新列将显示10/29/23,依此类推.

我们可以假设我只会处理2018年10月1日或之后的数据,所以这可能是双周周期开始的起点.第一个双周桶将是2018年10月1日至2018年10月14日,标签为10/14/2018.

如果可能,这需要完全包含在SELECT语句中,而不是使用GROUP BY.我只是将一个额外的计算列作为结果集添加到现有表中

我目前正在使用下面的SELECT,它将EndTime格式化为从周一到周日的weekly桶.

SELECT
    BunchOfOtherColumns
    ,FORMAT(DATEADD(DAY, 7 - DATEPART(WEEKDAY, EndTime), EndTime), 'MM/dd/yy')
FROM ...

这为我提供了一个很好的输出

BunchOfOtherColumns DateBucket

但现在我需要两周一次的水桶

以下是一批样本数据:

StartTime EndTime OtherColumns
2023-10-01 10:00:00 2023-10-01 23:59:00 Nope
2023-10-02 09:00:00 2023-10-02 12:59:00 Nada
2023-10-12 15:00:00 2023-10-12 17:59:00 Nyet
2023-10-27 10:00:00 2023-10-27 23:59:00 None

预期yields

OtherColumns BiWeeklyBucket
Nope 10/01/2023
Nada 10/15/2023
Nyet 10/15/2023
None 10/29/2023

推荐答案

(If using SQL Server 2022 or later, see the much simpler answer from Charlieface.)

给定定义任何两周时段的第一个星期一的参考日期,您可以计算天数差,然后计算FLOOR(diff / 14.0)以获得时段编号,或计算((diff % 14) + 14) % 14以计算相对于包含两周时段的开始星期一的天数.

要处理负偏移,需要使用FLOOR(diff / 14.0),而不是只使用diff / 14.同样,((diff % 14 + 14) % 14中的双模数也需要将负数映射到所需的0..13范围.

DECLARE @ReferenceDate DATE = '2023-10-02' -- Reference Monday

;WITH CTE_Dates AS (
    SELECT CONVERT(DATETIME, '2023-09-01 13:45') Dt
    UNION ALL
    SELECT DATEADD(day, 1, D.Dt) AS Dt
    FROM CTE_Dates D
    WHERE D.Dt < '2023-10-31'
)
SELECT
    D.Dt,
    DATENAME(weekday, D.Dt) AS WeekDay,
    DATEDIFF(day, @ReferenceDate, D.Dt) AS DayDiff,
    FLOOR(DATEDIFF(day, @ReferenceDate, D.Dt) / 14.0) AS BucketNo,
    ((DATEDIFF(day, @ReferenceDate, D.Dt) % 14) + 14) % 14 AS BucketDay,
    CONVERT(DATE, DATEADD(day, - ((DATEDIFF(day, @ReferenceDate, D.Dt) % 14) + 14) % 14, D.Dt)) AS BucketStartDt,
    CONVERT(DATE, DATEADD(day, 13 - ((DATEDIFF(day, @ReferenceDate, D.Dt) % 14) + 14) % 14, D.Dt)) AS BucketEndDt
FROM CTE_Dates D
OPTION (MAXRECURSION 1000)

部分结果:

Dt WeekDay DayDiff BucketNo BucketDay BucketStartDt BucketEndDt
2023-10-01 13:45 Sunday -1 -1 13 2023-09-18 2023-10-01
2023-10-02 13:45 Monday 0 0 0 2023-10-02 2023-10-15
2023-10-03 13:45 Tuesday 1 0 1 2023-10-02 2023-10-15
2023-10-04 13:45 Wednesday 2 0 2 2023-10-02 2023-10-15
2023-10-05 13:45 Thursday 3 0 3 2023-10-02 2023-10-15
2023-10-06 13:45 Friday 4 0 4 2023-10-02 2023-10-15
2023-10-07 13:45 Saturday 5 0 5 2023-10-02 2023-10-15
2023-10-08 13:45 Sunday 6 0 6 2023-10-02 2023-10-15
2023-10-09 13:45 Monday 7 0 7 2023-10-02 2023-10-15
2023-10-10 13:45 Tuesday 8 0 8 2023-10-02 2023-10-15
2023-10-11 13:45 Wednesday 9 0 9 2023-10-02 2023-10-15
2023-10-12 13:45 Thursday 10 0 10 2023-10-02 2023-10-15
2023-10-13 13:45 Friday 11 0 11 2023-10-02 2023-10-15
2023-10-14 13:45 Saturday 12 0 12 2023-10-02 2023-10-15
2023-10-15 13:45 Sunday 13 0 13 2023-10-02 2023-10-15
2023-10-16 13:45 Monday 14 1 0 2023-10-16 2023-10-29
2023-10-17 13:45 Tuesday 15 1 1 2023-10-16 2023-10-29
2023-10-18 13:45 Wednesday 16 1 2 2023-10-16 2023-10-29
2023-10-19 13:45 Thursday 17 1 3 2023-10-16 2023-10-29

请参见this db<>fiddle.

最初的帖子和随后的 comments 对于哪些星期一构成为期两周的桶的开始或中间并不一致,但可以根据需要更改@ReferenceDate个,以适应最终决定.(今天甚至不需要是星期一.)

Sql相关问答推荐

GROUP BY和GROUP_CONCAT用于计算比赛排名

如何从上一个值减go 值

为什么postgres中CURRENT_TIMESTAMP的日期与CURRENT_DATE不同?

Access 365将文本转换回BigInt

MariaDB查询在逗号分隔的字符串中查找多个值

SQL:计算与另一列中给定值互斥的匹配项

如何在PostgreSQL中的一列中添加两个文本?

PostgreSQL 9.6嵌套的INSERT/RETURN语句的CTE性能低得令人无法接受

我怎样才能得到列值对应的最大值在另一个?

获得第三名或最老的记录

根据开始日期和结束日期的差异计算每天的计费

SQL Server 查询 WHERE LIKE

列(值不为空)到其他有序列

获取上个月和上一年的值

当 2 列具有静态值并且第 3 列使用运算符 IN 时,对 PostgreSQL 和 3 列上的复杂索引的最佳查询

如何根据 SQL Server 中 1 条语句中 SELECT 的结果进行 INSERT 或 UPDATE

避免在SQL中使用具有相同条件的多个子查询

删除重复记录但保留最新的SQL查询

Oracle函数中无法动态迭代创建的SYS_REFCURSOR

如何筛选 GROUP BY 结果? HAVING 没有产生预期的结果